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.mysticeti_fastpath() {
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;
245 use consensus_types::block::{BlockDigest, BlockRef, TransactionIndex};
246 use sui_protocol_config::ProtocolConfig;
247
248 use super::*;
249 use crate::{
250 block::{TestBlock, Transaction},
251 context::Context,
252 transaction::{TransactionVerifier, ValidationError},
253 };
254
255 struct TxnSizeVerifier {}
256
257 impl TransactionVerifier for TxnSizeVerifier {
258 fn verify_batch(&self, transactions: &[&[u8]]) -> Result<(), ValidationError> {
260 for txn in transactions {
261 if txn.len() < 4 {
262 return Err(ValidationError::InvalidTransaction(format!(
263 "Length {} is too short!",
264 txn.len()
265 )));
266 }
267 }
268 Ok(())
269 }
270
271 fn verify_and_vote_batch(
274 &self,
275 _block_ref: &BlockRef,
276 batch: &[&[u8]],
277 ) -> Result<Vec<TransactionIndex>, ValidationError> {
278 let mut rejected_indices = vec![];
279 for (i, txn) in batch.iter().enumerate() {
280 if txn.len() < 4 {
281 return Err(ValidationError::InvalidTransaction(format!(
282 "Length {} is too short!",
283 txn.len()
284 )));
285 }
286 if txn.len() < 16 {
287 rejected_indices.push(i as TransactionIndex);
288 }
289 }
290 Ok(rejected_indices)
291 }
292 }
293
294 #[tokio::test]
295 async fn test_verify_block() {
296 let (context, keypairs) = Context::new_for_test(4);
297 let context = Arc::new(context);
298 const AUTHOR: u32 = 2;
299 let author_protocol_keypair = &keypairs[AUTHOR as usize].1;
300 let verifier = SignedBlockVerifier::new(context.clone(), Arc::new(TxnSizeVerifier {}));
301
302 let test_block = TestBlock::new(10, AUTHOR)
303 .set_ancestors(vec![
304 BlockRef::new(9, AuthorityIndex::new_for_test(2), BlockDigest::MIN),
305 BlockRef::new(9, AuthorityIndex::new_for_test(0), BlockDigest::MIN),
306 BlockRef::new(9, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
307 BlockRef::new(7, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
308 ])
309 .set_transactions(vec![Transaction::new(vec![4; 8])]);
310
311 {
313 let block = test_block.clone().build();
314 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
315 verifier.verify_block(&signed_block).unwrap();
316 }
317
318 {
320 let block = test_block.clone().set_epoch(1).build();
321 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
322 assert!(matches!(
323 verifier.verify_block(&signed_block),
324 Err(ConsensusError::WrongEpoch {
325 expected: _,
326 actual: _
327 })
328 ));
329 }
330
331 {
333 let block = test_block.clone().set_round(0).build();
334 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
335 assert!(matches!(
336 verifier.verify_block(&signed_block),
337 Err(ConsensusError::UnexpectedGenesisBlock)
338 ));
339 }
340
341 {
343 let block = test_block
344 .clone()
345 .set_author(AuthorityIndex::new_for_test(4))
346 .build();
347 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
348 assert!(matches!(
349 verifier.verify_block(&signed_block),
350 Err(ConsensusError::InvalidAuthorityIndex { index: _, max: _ })
351 ));
352 }
353
354 {
356 let block = test_block
357 .clone()
358 .set_author(AuthorityIndex::new_for_test(1))
359 .build();
360 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
361 assert!(matches!(
362 verifier.verify_block(&signed_block),
363 Err(ConsensusError::SignatureVerificationFailure(_))
364 ));
365 }
366
367 {
369 let block = test_block.clone().build();
370 let signed_block = SignedBlock::new(block, &keypairs[3].1).unwrap();
371 assert!(matches!(
372 verifier.verify_block(&signed_block),
373 Err(ConsensusError::SignatureVerificationFailure(_))
374 ));
375 }
376
377 {
379 let block = test_block.clone().build();
380 let mut signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
381 signed_block.clear_signature();
382 assert!(matches!(
383 verifier.verify_block(&signed_block),
384 Err(ConsensusError::MalformedSignature(_))
385 ));
386 }
387
388 {
390 let block = test_block
391 .clone()
392 .set_ancestors(vec![
393 BlockRef::new(9, AuthorityIndex::new_for_test(2), BlockDigest::MIN),
394 BlockRef::new(9, AuthorityIndex::new_for_test(0), BlockDigest::MIN),
395 BlockRef::new(9, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
396 BlockRef::new(10, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
397 ])
398 .build();
399 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
400 assert!(matches!(
401 verifier.verify_block(&signed_block),
402 Err(ConsensusError::InvalidAncestorRound {
403 ancestor: _,
404 block: _
405 })
406 ));
407 }
408
409 {
411 let block = test_block
412 .clone()
413 .set_ancestors(vec![
414 BlockRef::new(9, AuthorityIndex::new_for_test(2), BlockDigest::MIN),
415 BlockRef::new(9, AuthorityIndex::new_for_test(0), BlockDigest::MIN),
416 BlockRef::new(8, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
417 BlockRef::new(8, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
418 ])
419 .build();
420 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
421 assert!(matches!(
422 verifier.verify_block(&signed_block),
423 Err(ConsensusError::InsufficientParentStakes {
424 parent_stakes: _,
425 quorum: _
426 })
427 ));
428 }
429
430 {
432 let block = test_block
433 .clone()
434 .set_ancestors(vec![
435 BlockRef::new(9, AuthorityIndex::new_for_test(2), BlockDigest::MIN),
436 BlockRef::new(9, AuthorityIndex::new_for_test(0), BlockDigest::MIN),
437 BlockRef::new(8, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
438 BlockRef::new(8, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
439 BlockRef::new(9, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
440 ])
441 .build();
442 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
443 assert!(matches!(
444 verifier.verify_block(&signed_block),
445 Err(ConsensusError::TooManyAncestors(_, _))
446 ));
447 }
448
449 {
451 let block = test_block
452 .clone()
453 .set_ancestors(vec![
454 BlockRef::new(9, AuthorityIndex::new_for_test(0), BlockDigest::MIN),
455 BlockRef::new(8, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
456 BlockRef::new(8, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
457 ])
458 .build();
459 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
460 assert!(matches!(
461 verifier.verify_block(&signed_block),
462 Err(ConsensusError::InvalidAncestorPosition {
463 block_authority: _,
464 ancestor_authority: _,
465 position: _
466 })
467 ));
468 }
469
470 {
472 let block = test_block
473 .clone()
474 .set_ancestors(vec![
475 BlockRef::new(9, AuthorityIndex::new_for_test(0), BlockDigest::MIN),
476 BlockRef::new(8, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
477 BlockRef::new(8, AuthorityIndex::new_for_test(2), BlockDigest::MIN),
478 BlockRef::new(8, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
479 ])
480 .build();
481 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
482 assert!(matches!(
483 verifier.verify_block(&signed_block),
484 Err(ConsensusError::InvalidAncestorPosition {
485 block_authority: _,
486 ancestor_authority: _,
487 position: _
488 })
489 ));
490 }
491
492 {
494 let block = test_block
495 .clone()
496 .set_ancestors(vec![
497 BlockRef::new(8, AuthorityIndex::new_for_test(2), BlockDigest::MIN),
498 BlockRef::new(8, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
499 BlockRef::new(8, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
500 ])
501 .build();
502 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
503 assert!(matches!(
504 verifier.verify_block(&signed_block),
505 Err(ConsensusError::DuplicatedAncestorsAuthority(_))
506 ));
507 }
508
509 {
511 let block = test_block
512 .clone()
513 .set_transactions(vec![Transaction::new(vec![4; 257 * 1024])])
514 .build();
515 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
516 assert!(matches!(
517 verifier.verify_block(&signed_block),
518 Err(ConsensusError::TransactionTooLarge { size: _, limit: _ })
519 ));
520 }
521
522 {
524 let block = test_block
525 .clone()
526 .set_transactions((0..1000).map(|_| Transaction::new(vec![4; 8])).collect())
527 .build();
528 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
529 assert!(matches!(
530 verifier.verify_block(&signed_block),
531 Err(ConsensusError::TooManyTransactions { count: _, limit: _ })
532 ));
533 }
534
535 {
537 let block = test_block
538 .clone()
539 .set_transactions(
540 (0..100)
541 .map(|_| Transaction::new(vec![4; 8 * 1024]))
542 .collect(),
543 )
544 .build();
545 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
546 assert!(matches!(
547 verifier.verify_block(&signed_block),
548 Err(ConsensusError::TooManyTransactionBytes { size: _, limit: _ })
549 ));
550 }
551
552 {
554 let block = test_block
555 .clone()
556 .set_transactions(vec![
557 Transaction::new(vec![1; 4]),
558 Transaction::new(vec![1; 2]),
559 ])
560 .build();
561 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
562 let serialized_block = signed_block
563 .serialize()
564 .expect("Block serialization failed.");
565 assert!(matches!(
566 verifier.verify_and_vote(signed_block, serialized_block),
567 Err(ConsensusError::InvalidTransaction(_))
568 ));
569 }
570 }
571
572 #[tokio::test]
573 async fn test_verify_and_vote_transactions() {
574 let mut protocol_config = ProtocolConfig::get_for_max_version_UNSAFE();
575 protocol_config.set_mysticeti_fastpath_for_testing(true);
576
577 let (context, keypairs) = Context::new_for_test(4);
578 let context = Arc::new(context.with_protocol_config(protocol_config));
579
580 const AUTHOR: u32 = 2;
581 let author_protocol_keypair = &keypairs[AUTHOR as usize].1;
582 let verifier = SignedBlockVerifier::new(context.clone(), Arc::new(TxnSizeVerifier {}));
583
584 let base_block = TestBlock::new(10, AUTHOR).set_ancestors(vec![
585 BlockRef::new(9, AuthorityIndex::new_for_test(2), BlockDigest::MIN),
586 BlockRef::new(9, AuthorityIndex::new_for_test(0), BlockDigest::MIN),
587 BlockRef::new(9, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
588 BlockRef::new(7, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
589 ]);
590
591 {
593 let block = base_block
594 .clone()
595 .set_transactions(vec![
596 Transaction::new(vec![1; 16]),
597 Transaction::new(vec![2; 16]),
598 Transaction::new(vec![3; 16]),
599 Transaction::new(vec![4; 16]),
600 ])
601 .build();
602 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
603 let serialized_block = signed_block
604 .serialize()
605 .expect("Block serialization failed.");
606 let (verified_block, rejected_transactions) = verifier
607 .verify_and_vote(signed_block, serialized_block.clone())
608 .unwrap();
609 assert_eq!(rejected_transactions, Vec::<TransactionIndex>::new());
610 assert_eq!(verified_block.serialized().clone(), serialized_block);
611 }
612
613 {
615 let block = base_block
616 .clone()
617 .set_transactions(vec![
618 Transaction::new(vec![1; 16]),
619 Transaction::new(vec![2; 8]),
620 Transaction::new(vec![3; 16]),
621 Transaction::new(vec![4; 9]),
622 ])
623 .build();
624 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
625 let serialized_block = signed_block
626 .serialize()
627 .expect("Block serialization failed.");
628 let (_verified_block, rejected_transactions) = verifier
629 .verify_and_vote(signed_block, serialized_block)
630 .unwrap();
631 assert_eq!(
632 rejected_transactions,
633 vec![1 as TransactionIndex, 3 as TransactionIndex],
634 );
635 }
636
637 {
639 let block = base_block
640 .clone()
641 .set_transactions(vec![
642 Transaction::new(vec![1; 16]),
643 Transaction::new(vec![2; 8]),
644 Transaction::new(vec![3; 1]), Transaction::new(vec![4; 9]),
646 ])
647 .build();
648 let signed_block = SignedBlock::new(block, author_protocol_keypair).unwrap();
649 let serialized_block = signed_block
650 .serialize()
651 .expect("Block serialization failed.");
652 assert!(matches!(
653 verifier.verify_and_vote(signed_block, serialized_block),
654 Err(ConsensusError::InvalidTransaction(_))
655 ));
656 }
657 }
658}