1use bytes::Bytes;
5use consensus_types::block::{BlockRef, TransactionIndex};
6use std::{collections::BTreeSet, sync::Arc};
7
8use crate::{
9 VerifiedBlock,
10 block::{BlockAPI, GENESIS_ROUND, SignedBlock, genesis_blocks},
11 context::Context,
12 error::{ConsensusError, ConsensusResult},
13 transaction::TransactionVerifier,
14};
15
16pub trait BlockVerifier: Send + Sync + 'static {
17 #[allow(private_interfaces)]
28 fn verify_and_vote(
29 &self,
30 block: SignedBlock,
31 serialized_block: Bytes,
32 ) -> ConsensusResult<(VerifiedBlock, Vec<TransactionIndex>)>;
33
34 fn vote(&self, block: &VerifiedBlock) -> ConsensusResult<Vec<TransactionIndex>>;
38}
39
40pub(crate) struct SignedBlockVerifier {
46 context: Arc<Context>,
47 genesis: BTreeSet<BlockRef>,
48 transaction_verifier: Arc<dyn TransactionVerifier>,
49}
50
51impl SignedBlockVerifier {
52 pub(crate) fn new(
53 context: Arc<Context>,
54 transaction_verifier: Arc<dyn TransactionVerifier>,
55 ) -> Self {
56 let genesis = genesis_blocks(&context)
57 .into_iter()
58 .map(|b| b.reference())
59 .collect();
60 Self {
61 context,
62 genesis,
63 transaction_verifier,
64 }
65 }
66
67 fn verify_block(&self, block: &SignedBlock) -> ConsensusResult<()> {
68 let committee = &self.context.committee;
69 if block.epoch() != committee.epoch() {
72 return Err(ConsensusError::WrongEpoch {
73 expected: committee.epoch(),
74 actual: block.epoch(),
75 });
76 }
77 if block.round() == 0 {
78 return Err(ConsensusError::UnexpectedGenesisBlock);
79 }
80 if !committee.is_valid_index(block.author()) {
81 return Err(ConsensusError::InvalidAuthorityIndex {
82 index: block.author(),
83 max: committee.size() - 1,
84 });
85 }
86
87 block.verify_signature(&self.context)?;
89
90 if block.ancestors().len() > committee.size() {
93 return Err(ConsensusError::TooManyAncestors(
94 block.ancestors().len(),
95 committee.size(),
96 ));
97 }
98 if block.ancestors().is_empty() {
99 return Err(ConsensusError::InsufficientParentStakes {
100 parent_stakes: 0,
101 quorum: committee.quorum_threshold(),
102 });
103 }
104 let mut seen_ancestors = vec![false; committee.size()];
105 let mut parent_stakes = 0;
106 for (i, ancestor) in block.ancestors().iter().enumerate() {
107 if !committee.is_valid_index(ancestor.author) {
108 return Err(ConsensusError::InvalidAuthorityIndex {
109 index: ancestor.author,
110 max: committee.size() - 1,
111 });
112 }
113 if (i == 0 && ancestor.author != block.author())
114 || (i > 0 && ancestor.author == block.author())
115 {
116 return Err(ConsensusError::InvalidAncestorPosition {
117 block_authority: block.author(),
118 ancestor_authority: ancestor.author,
119 position: i,
120 });
121 }
122 if ancestor.round >= block.round() {
123 return Err(ConsensusError::InvalidAncestorRound {
124 ancestor: ancestor.round,
125 block: block.round(),
126 });
127 }
128 if ancestor.round == GENESIS_ROUND && !self.genesis.contains(ancestor) {
129 return Err(ConsensusError::InvalidGenesisAncestor(*ancestor));
130 }
131 if seen_ancestors[ancestor.author] {
132 return Err(ConsensusError::DuplicatedAncestorsAuthority(
133 ancestor.author,
134 ));
135 }
136 seen_ancestors[ancestor.author] = true;
137 if ancestor.round == block.round().checked_sub(1).unwrap() {
139 parent_stakes += committee.stake(ancestor.author);
140 }
141 }
142 if !committee.reached_quorum(parent_stakes) {
143 return Err(ConsensusError::InsufficientParentStakes {
144 parent_stakes,
145 quorum: committee.quorum_threshold(),
146 });
147 }
148
149 let batch: Vec<_> = block.transactions().iter().map(|t| t.data()).collect();
150
151 self.check_transactions(&batch)
152 }
153
154 pub(crate) fn check_transactions(&self, batch: &[&[u8]]) -> ConsensusResult<()> {
155 let max_transaction_size_limit =
156 self.context.protocol_config.max_transaction_size_bytes() as usize;
157 for t in batch {
158 if t.len() > max_transaction_size_limit && max_transaction_size_limit > 0 {
159 return Err(ConsensusError::TransactionTooLarge {
160 size: t.len(),
161 limit: max_transaction_size_limit,
162 });
163 }
164 }
165
166 let max_num_transactions_limit =
167 self.context.protocol_config.max_num_transactions_in_block() as usize;
168 if batch.len() > max_num_transactions_limit && max_num_transactions_limit > 0 {
169 return Err(ConsensusError::TooManyTransactions {
170 count: batch.len(),
171 limit: max_num_transactions_limit,
172 });
173 }
174
175 let total_transactions_size_limit = self
176 .context
177 .protocol_config
178 .max_transactions_in_block_bytes() as usize;
179 if batch.iter().map(|t| t.len()).sum::<usize>() > total_transactions_size_limit
180 && total_transactions_size_limit > 0
181 {
182 return Err(ConsensusError::TooManyTransactionBytes {
183 size: batch.len(),
184 limit: total_transactions_size_limit,
185 });
186 }
187 Ok(())
188 }
189}
190
191impl BlockVerifier for SignedBlockVerifier {
193 fn verify_and_vote(
194 &self,
195 block: SignedBlock,
196 serialized_block: Bytes,
197 ) -> ConsensusResult<(VerifiedBlock, Vec<TransactionIndex>)> {
198 self.verify_block(&block)?;
199
200 let verified_block = VerifiedBlock::new_verified(block, serialized_block);
202
203 let rejected_transactions = if self.context.protocol_config.transaction_voting_enabled() {
204 self.vote(&verified_block)?
205 } else {
206 self.transaction_verifier
207 .verify_batch(&verified_block.transactions_data())
208 .map_err(|e| ConsensusError::InvalidTransaction(e.to_string()))?;
209 vec![]
210 };
211 Ok((verified_block, rejected_transactions))
212 }
213
214 fn vote(&self, block: &VerifiedBlock) -> ConsensusResult<Vec<TransactionIndex>> {
215 self.transaction_verifier
216 .verify_and_vote_batch(&block.reference(), &block.transactions_data())
217 .map_err(|e| ConsensusError::InvalidTransaction(e.to_string()))
218 }
219}
220
221pub struct NoopBlockVerifier;
223
224impl BlockVerifier for NoopBlockVerifier {
225 #[allow(private_interfaces)]
226 fn verify_and_vote(
227 &self,
228 _block: SignedBlock,
229 _serialized_block: Bytes,
230 ) -> ConsensusResult<(VerifiedBlock, Vec<TransactionIndex>)> {
231 Ok((
232 VerifiedBlock::new_verified(_block, _serialized_block),
233 vec![],
234 ))
235 }
236
237 fn vote(&self, _block: &VerifiedBlock) -> ConsensusResult<Vec<TransactionIndex>> {
238 Ok(vec![])
239 }
240}
241
242#[cfg(test)]
243mod test {
244 use consensus_config::{AuthorityIndex, ConsensusProtocolConfig};
245 use consensus_types::block::{BlockDigest, BlockRef, TransactionIndex};
246
247 use super::*;
248 use crate::{
249 block::{TestBlock, Transaction},
250 context::Context,
251 transaction::{TransactionVerifier, ValidationError},
252 };
253
254 struct TxnSizeVerifier {}
255
256 impl TransactionVerifier for TxnSizeVerifier {
257 fn verify_batch(&self, transactions: &[&[u8]]) -> Result<(), ValidationError> {
259 for txn in transactions {
260 if txn.len() < 4 {
261 return Err(ValidationError::InvalidTransaction(format!(
262 "Length {} is too short!",
263 txn.len()
264 )));
265 }
266 }
267 Ok(())
268 }
269
270 fn verify_and_vote_batch(
273 &self,
274 _block_ref: &BlockRef,
275 batch: &[&[u8]],
276 ) -> Result<Vec<TransactionIndex>, ValidationError> {
277 let mut rejected_indices = vec![];
278 for (i, txn) in batch.iter().enumerate() {
279 if txn.len() < 4 {
280 return Err(ValidationError::InvalidTransaction(format!(
281 "Length {} is too short!",
282 txn.len()
283 )));
284 }
285 if txn.len() < 16 {
286 rejected_indices.push(i as TransactionIndex);
287 }
288 }
289 Ok(rejected_indices)
290 }
291 }
292
293 #[tokio::test]
294 async fn test_verify_block() {
295 let (context, keypairs) = Context::new_for_test(4);
296 let context = Arc::new(context);
297 const AUTHOR: u32 = 2;
298 let author_protocol_keypair = &keypairs[AUTHOR as usize].1;
299 let verifier = SignedBlockVerifier::new(context.clone(), Arc::new(TxnSizeVerifier {}));
300
301 let test_block = TestBlock::new(10, AUTHOR)
302 .set_ancestors_raw(vec![
303 BlockRef::new(9, AuthorityIndex::new_for_test(2), BlockDigest::MIN),
304 BlockRef::new(9, AuthorityIndex::new_for_test(0), BlockDigest::MIN),
305 BlockRef::new(9, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
306 BlockRef::new(7, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
307 ])
308 .set_transactions(vec![Transaction::new(vec![4; 8])]);
309
310 {
312 let block = test_block.clone().build();
313 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
314 verifier.verify_block(&signed_block).unwrap();
315 }
316
317 {
319 let block = test_block.clone().set_epoch(1).build();
320 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
321 assert!(matches!(
322 verifier.verify_block(&signed_block),
323 Err(ConsensusError::WrongEpoch {
324 expected: _,
325 actual: _
326 })
327 ));
328 }
329
330 {
332 let block = test_block.clone().set_round(0).build();
333 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
334 assert!(matches!(
335 verifier.verify_block(&signed_block),
336 Err(ConsensusError::UnexpectedGenesisBlock)
337 ));
338 }
339
340 {
342 let block = test_block
343 .clone()
344 .set_author(AuthorityIndex::new_for_test(4))
345 .build();
346 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
347 assert!(matches!(
348 verifier.verify_block(&signed_block),
349 Err(ConsensusError::InvalidAuthorityIndex { index: _, max: _ })
350 ));
351 }
352
353 {
355 let block = test_block
356 .clone()
357 .set_author(AuthorityIndex::new_for_test(1))
358 .build();
359 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
360 assert!(matches!(
361 verifier.verify_block(&signed_block),
362 Err(ConsensusError::SignatureVerificationFailure(_))
363 ));
364 }
365
366 {
368 let block = test_block.clone().build();
369 let signed_block = SignedBlock::new(block, &keypairs[3].1).unwrap();
370 assert!(matches!(
371 verifier.verify_block(&signed_block),
372 Err(ConsensusError::SignatureVerificationFailure(_))
373 ));
374 }
375
376 {
378 let block = test_block.clone().build();
379 let mut signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
380 signed_block.clear_signature();
381 assert!(matches!(
382 verifier.verify_block(&signed_block),
383 Err(ConsensusError::MalformedSignature(_))
384 ));
385 }
386
387 {
389 let block = test_block
390 .clone()
391 .set_ancestors_raw(vec![
392 BlockRef::new(9, AuthorityIndex::new_for_test(2), BlockDigest::MIN),
393 BlockRef::new(9, AuthorityIndex::new_for_test(0), BlockDigest::MIN),
394 BlockRef::new(9, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
395 BlockRef::new(10, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
396 ])
397 .build();
398 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
399 assert!(matches!(
400 verifier.verify_block(&signed_block),
401 Err(ConsensusError::InvalidAncestorRound {
402 ancestor: _,
403 block: _
404 })
405 ));
406 }
407
408 {
410 let block = test_block
411 .clone()
412 .set_ancestors_raw(vec![
413 BlockRef::new(9, AuthorityIndex::new_for_test(2), BlockDigest::MIN),
414 BlockRef::new(9, AuthorityIndex::new_for_test(0), BlockDigest::MIN),
415 BlockRef::new(8, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
416 BlockRef::new(8, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
417 ])
418 .build();
419 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
420 assert!(matches!(
421 verifier.verify_block(&signed_block),
422 Err(ConsensusError::InsufficientParentStakes {
423 parent_stakes: _,
424 quorum: _
425 })
426 ));
427 }
428
429 {
431 let block = test_block
432 .clone()
433 .set_ancestors_raw(vec![
434 BlockRef::new(9, AuthorityIndex::new_for_test(2), BlockDigest::MIN),
435 BlockRef::new(9, AuthorityIndex::new_for_test(0), BlockDigest::MIN),
436 BlockRef::new(8, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
437 BlockRef::new(8, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
438 BlockRef::new(9, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
439 ])
440 .build();
441 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
442 assert!(matches!(
443 verifier.verify_block(&signed_block),
444 Err(ConsensusError::TooManyAncestors(_, _))
445 ));
446 }
447
448 {
450 let block = test_block
451 .clone()
452 .set_ancestors_raw(vec![
453 BlockRef::new(9, AuthorityIndex::new_for_test(0), BlockDigest::MIN),
454 BlockRef::new(8, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
455 BlockRef::new(8, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
456 ])
457 .build();
458 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
459 assert!(matches!(
460 verifier.verify_block(&signed_block),
461 Err(ConsensusError::InvalidAncestorPosition {
462 block_authority: _,
463 ancestor_authority: _,
464 position: _
465 })
466 ));
467 }
468
469 {
471 let block = test_block
472 .clone()
473 .set_ancestors_raw(vec![
474 BlockRef::new(9, AuthorityIndex::new_for_test(0), BlockDigest::MIN),
475 BlockRef::new(8, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
476 BlockRef::new(8, AuthorityIndex::new_for_test(2), BlockDigest::MIN),
477 BlockRef::new(8, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
478 ])
479 .build();
480 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
481 assert!(matches!(
482 verifier.verify_block(&signed_block),
483 Err(ConsensusError::InvalidAncestorPosition {
484 block_authority: _,
485 ancestor_authority: _,
486 position: _
487 })
488 ));
489 }
490
491 {
493 let block = test_block
494 .clone()
495 .set_ancestors_raw(vec![
496 BlockRef::new(8, AuthorityIndex::new_for_test(2), BlockDigest::MIN),
497 BlockRef::new(8, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
498 BlockRef::new(8, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
499 ])
500 .build();
501 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
502 assert!(matches!(
503 verifier.verify_block(&signed_block),
504 Err(ConsensusError::DuplicatedAncestorsAuthority(_))
505 ));
506 }
507
508 {
510 let block = test_block
511 .clone()
512 .set_transactions(vec![Transaction::new(vec![4; 257 * 1024])])
513 .build();
514 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
515 assert!(matches!(
516 verifier.verify_block(&signed_block),
517 Err(ConsensusError::TransactionTooLarge { size: _, limit: _ })
518 ));
519 }
520
521 {
523 let block = test_block
524 .clone()
525 .set_transactions((0..1000).map(|_| Transaction::new(vec![4; 8])).collect())
526 .build();
527 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
528 assert!(matches!(
529 verifier.verify_block(&signed_block),
530 Err(ConsensusError::TooManyTransactions { count: _, limit: _ })
531 ));
532 }
533
534 {
536 let block = test_block
537 .clone()
538 .set_transactions(
539 (0..100)
540 .map(|_| Transaction::new(vec![4; 8 * 1024]))
541 .collect(),
542 )
543 .build();
544 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
545 assert!(matches!(
546 verifier.verify_block(&signed_block),
547 Err(ConsensusError::TooManyTransactionBytes { size: _, limit: _ })
548 ));
549 }
550
551 {
553 let block = test_block
554 .clone()
555 .set_transactions(vec![
556 Transaction::new(vec![1; 4]),
557 Transaction::new(vec![1; 2]),
558 ])
559 .build();
560 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
561 let serialized_block = signed_block
562 .serialize()
563 .expect("Block serialization failed.");
564 assert!(matches!(
565 verifier.verify_and_vote(signed_block, serialized_block),
566 Err(ConsensusError::InvalidTransaction(_))
567 ));
568 }
569 }
570
571 #[tokio::test]
572 async fn test_verify_and_vote_transactions() {
573 let mut protocol_config = ConsensusProtocolConfig::for_testing();
574 protocol_config.set_transaction_voting_enabled_for_testing(true);
575
576 let (context, keypairs) = Context::new_for_test(4);
577 let context = Arc::new(context.with_protocol_config(protocol_config));
578
579 const AUTHOR: u32 = 2;
580 let author_protocol_keypair = &keypairs[AUTHOR as usize].1;
581 let verifier = SignedBlockVerifier::new(context.clone(), Arc::new(TxnSizeVerifier {}));
582
583 let base_block = TestBlock::new(10, AUTHOR).set_ancestors_raw(vec![
584 BlockRef::new(9, AuthorityIndex::new_for_test(2), BlockDigest::MIN),
585 BlockRef::new(9, AuthorityIndex::new_for_test(0), BlockDigest::MIN),
586 BlockRef::new(9, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
587 BlockRef::new(7, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
588 ]);
589
590 {
592 let block = base_block
593 .clone()
594 .set_transactions(vec![
595 Transaction::new(vec![1; 16]),
596 Transaction::new(vec![2; 16]),
597 Transaction::new(vec![3; 16]),
598 Transaction::new(vec![4; 16]),
599 ])
600 .build();
601 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
602 let serialized_block = signed_block
603 .serialize()
604 .expect("Block serialization failed.");
605 let (verified_block, rejected_transactions) = verifier
606 .verify_and_vote(signed_block, serialized_block.clone())
607 .unwrap();
608 assert_eq!(rejected_transactions, Vec::<TransactionIndex>::new());
609 assert_eq!(verified_block.serialized().clone(), serialized_block);
610 }
611
612 {
614 let block = base_block
615 .clone()
616 .set_transactions(vec![
617 Transaction::new(vec![1; 16]),
618 Transaction::new(vec![2; 8]),
619 Transaction::new(vec![3; 16]),
620 Transaction::new(vec![4; 9]),
621 ])
622 .build();
623 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
624 let serialized_block = signed_block
625 .serialize()
626 .expect("Block serialization failed.");
627 let (_verified_block, rejected_transactions) = verifier
628 .verify_and_vote(signed_block, serialized_block)
629 .unwrap();
630 assert_eq!(
631 rejected_transactions,
632 vec![1 as TransactionIndex, 3 as TransactionIndex],
633 );
634 }
635
636 {
638 let block = base_block
639 .clone()
640 .set_transactions(vec![
641 Transaction::new(vec![1; 16]),
642 Transaction::new(vec![2; 8]),
643 Transaction::new(vec![3; 1]), Transaction::new(vec![4; 9]),
645 ])
646 .build();
647 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
648 let serialized_block = signed_block
649 .serialize()
650 .expect("Block serialization failed.");
651 assert!(matches!(
652 verifier.verify_and_vote(signed_block, serialized_block),
653 Err(ConsensusError::InvalidTransaction(_))
654 ));
655 }
656 }
657}