1use std::{
5 collections::{BTreeMap, HashSet},
6 ops::{Bound::Included, RangeInclusive},
7 sync::Arc,
8};
9
10use consensus_config::AuthorityIndex;
11use consensus_types::block::{BlockDigest, BlockRef, BlockTimestampMs, Round, TransactionIndex};
12use parking_lot::RwLock;
13use rand::{Rng, SeedableRng, rngs::StdRng, seq::SliceRandom, thread_rng};
14
15#[cfg(test)]
16use crate::commit::CertifiedCommit;
17use crate::{
18 CommitRef, CommittedSubDag, Transaction,
19 block::{BlockAPI, BlockTransactionVotes, Slot, TestBlock, VerifiedBlock, genesis_blocks},
20 commit::{CommitDigest, TrustedCommit},
21 context::Context,
22 dag_state::DagState,
23 leader_schedule::{LeaderSchedule, LeaderSwapTable},
24 linearizer::{BlockStoreAPI, Linearizer},
25};
26
27pub struct DagBuilder {
77 pub(crate) context: Arc<Context>,
78 pub(crate) leader_schedule: LeaderSchedule,
79 pub(crate) genesis: BTreeMap<BlockRef, VerifiedBlock>,
81 pub(crate) last_ancestors: Vec<BlockRef>,
83 pub(crate) blocks: BTreeMap<BlockRef, VerifiedBlock>,
86 pub(crate) committed_sub_dags: Vec<(CommittedSubDag, TrustedCommit)>,
88 pub(crate) last_committed_rounds: Vec<Round>,
89
90 number_of_leaders: u32,
91}
92
93impl DagBuilder {
94 pub fn new(context: Arc<Context>) -> Self {
95 let leader_schedule = LeaderSchedule::new(context.clone(), LeaderSwapTable::default());
96 let genesis_blocks = genesis_blocks(context.as_ref());
97 let genesis: BTreeMap<BlockRef, VerifiedBlock> = genesis_blocks
98 .into_iter()
99 .map(|block| (block.reference(), block))
100 .collect();
101 let last_ancestors = genesis.keys().cloned().collect();
102 Self {
103 last_committed_rounds: vec![0; context.committee.size()],
104 context,
105 leader_schedule,
106 number_of_leaders: 1,
107 genesis,
108 last_ancestors,
109 blocks: BTreeMap::new(),
110 committed_sub_dags: vec![],
111 }
112 }
113
114 pub fn blocks(&self, rounds: RangeInclusive<Round>) -> Vec<VerifiedBlock> {
115 assert!(
116 !self.blocks.is_empty(),
117 "No blocks have been created, please make sure that you have called build method"
118 );
119 self.blocks
120 .iter()
121 .filter_map(|(block_ref, block)| rounds.contains(&block_ref.round).then_some(block))
122 .cloned()
123 .collect::<Vec<VerifiedBlock>>()
124 }
125
126 pub fn all_blocks(&self) -> Vec<VerifiedBlock> {
127 assert!(
128 !self.blocks.is_empty(),
129 "No blocks have been created, please make sure that you have called build method"
130 );
131 self.blocks.values().cloned().collect()
132 }
133
134 pub fn get_sub_dag_and_commits(
135 &mut self,
136 leader_rounds: RangeInclusive<Round>,
137 ) -> Vec<(CommittedSubDag, TrustedCommit)> {
138 let (last_leader_round, mut last_commit_ref, mut last_timestamp_ms) =
139 if let Some((sub_dag, _)) = self.committed_sub_dags.last() {
140 (
141 sub_dag.leader.round,
142 sub_dag.commit_ref,
143 sub_dag.timestamp_ms,
144 )
145 } else {
146 (0, CommitRef::new(0, CommitDigest::MIN), 0)
147 };
148
149 struct BlockStorage {
150 gc_round: Round,
151 blocks: BTreeMap<BlockRef, (VerifiedBlock, bool)>, genesis: BTreeMap<BlockRef, VerifiedBlock>,
153 }
154 impl BlockStoreAPI for BlockStorage {
155 fn get_blocks(&self, refs: &[BlockRef]) -> Vec<Option<VerifiedBlock>> {
156 refs.iter()
157 .map(|block_ref| {
158 if block_ref.round == 0 {
159 return self.genesis.get(block_ref).cloned();
160 }
161 self.blocks
162 .get(block_ref)
163 .map(|(block, _committed)| block.clone())
164 })
165 .collect()
166 }
167
168 fn gc_round(&self) -> Round {
169 self.gc_round
170 }
171
172 fn set_committed(&mut self, block_ref: &BlockRef) -> bool {
173 let Some((_block, committed)) = self.blocks.get_mut(block_ref) else {
174 panic!("Block {:?} should be found in store", block_ref);
175 };
176 if !*committed {
177 *committed = true;
178 return true;
179 }
180 false
181 }
182
183 fn is_committed(&self, block_ref: &BlockRef) -> bool {
184 self.blocks
185 .get(block_ref)
186 .map(|(_, committed)| *committed)
187 .expect("Block should be found in store")
188 }
189 }
190
191 let mut storage = BlockStorage {
192 blocks: self
193 .blocks
194 .clone()
195 .into_iter()
196 .map(|(k, v)| (k, (v, false)))
197 .collect(),
198 genesis: self.genesis.clone(),
199 gc_round: 0,
200 };
201
202 for leader_block in self
204 .leader_blocks(last_leader_round + 1..=*leader_rounds.end())
205 .into_iter()
206 .flatten()
207 {
208 storage.gc_round = leader_block
210 .round()
211 .saturating_sub(1)
212 .saturating_sub(self.context.protocol_config.gc_depth());
213
214 let leader_block_ref = leader_block.reference();
215
216 let to_commit = Linearizer::linearize_sub_dag(leader_block.clone(), &mut storage);
217
218 last_timestamp_ms = Linearizer::calculate_commit_timestamp(
219 &self.context.clone(),
220 &mut storage,
221 &leader_block,
222 last_timestamp_ms,
223 );
224
225 for block in &to_commit {
227 self.last_committed_rounds[block.author()] =
228 self.last_committed_rounds[block.author()].max(block.round());
229 }
230
231 let commit = TrustedCommit::new_for_test(
232 last_commit_ref.index + 1,
233 last_commit_ref.digest,
234 last_timestamp_ms,
235 leader_block_ref,
236 to_commit
237 .iter()
238 .map(|block| block.reference())
239 .collect::<Vec<_>>(),
240 );
241
242 last_commit_ref = commit.reference();
243
244 let sub_dag = CommittedSubDag::new(
245 leader_block_ref,
246 to_commit,
247 last_timestamp_ms,
248 commit.reference(),
249 );
250
251 self.committed_sub_dags.push((sub_dag, commit));
252 }
253
254 self.committed_sub_dags
255 .clone()
256 .into_iter()
257 .filter(|(sub_dag, _)| leader_rounds.contains(&sub_dag.leader.round))
258 .collect()
259 }
260
261 #[cfg(test)]
262 pub(crate) fn get_sub_dag_and_certified_commits(
263 &mut self,
264 leader_rounds: RangeInclusive<Round>,
265 ) -> Vec<(CommittedSubDag, CertifiedCommit)> {
266 let commits = self.get_sub_dag_and_commits(leader_rounds);
267 commits
268 .into_iter()
269 .map(|(sub_dag, commit)| {
270 let certified_commit =
271 CertifiedCommit::new_certified(commit, sub_dag.blocks.clone());
272 (sub_dag, certified_commit)
273 })
274 .collect()
275 }
276
277 pub fn leader_blocks(&self, rounds: RangeInclusive<Round>) -> Vec<Option<VerifiedBlock>> {
278 assert!(
279 !self.blocks.is_empty(),
280 "No blocks have been created, please make sure that you have called build method"
281 );
282 rounds
283 .into_iter()
284 .map(|round| self.leader_block(round))
285 .collect()
286 }
287
288 pub fn leader_block(&self, round: Round) -> Option<VerifiedBlock> {
289 assert!(
290 !self.blocks.is_empty(),
291 "No blocks have been created, please make sure that you have called build method"
292 );
293 self.blocks
294 .iter()
295 .find(|(block_ref, _block)| {
296 block_ref.round == round
297 && block_ref.author == self.leader_schedule.elect_leader(round, 0)
298 })
299 .map(|(_block_ref, block)| block.clone())
300 }
301
302 pub fn layer(&mut self, round: Round) -> LayerBuilder<'_> {
303 LayerBuilder::new(self, round)
304 }
305
306 pub fn layers(&mut self, rounds: RangeInclusive<Round>) -> LayerBuilder<'_> {
307 let mut builder = LayerBuilder::new(self, *rounds.start());
308 builder.end_round = Some(*rounds.end());
309 builder
310 }
311
312 pub fn persist_all_blocks(&self, dag_state: Arc<RwLock<DagState>>) {
313 dag_state
314 .write()
315 .accept_blocks(self.blocks.values().cloned().collect());
316 }
317
318 pub fn print(&self) {
319 let mut dag_str = "DAG {\n".to_string();
320
321 let mut round = 0;
322 for block in self.blocks.values() {
323 if block.round() > round {
324 round = block.round();
325 dag_str.push_str(&format!("Round {round} : \n"));
326 }
327 dag_str.push_str(&format!(" Block {block:#?}\n"));
328 }
329 dag_str.push_str("}\n");
330
331 tracing::info!("{dag_str}");
332 }
333
334 pub fn layer_with_connections(
339 &mut self,
340 connections: Vec<(AuthorityIndex, Vec<BlockRef>)>,
341 round: Round,
342 ) {
343 let mut references = Vec::new();
344 for (authority, ancestors) in connections {
345 let author = authority.value() as u32;
346 let base_ts = round as BlockTimestampMs * 1000;
347 let block = VerifiedBlock::new_for_test(
348 TestBlock::new(round, author)
349 .set_ancestors(ancestors)
350 .set_timestamp_ms(base_ts + author as u64)
351 .build(),
352 );
353 references.push(block.reference());
354 self.blocks.insert(block.reference(), block.clone());
355 }
356 self.last_ancestors = references;
357 }
358
359 pub fn get_uncommitted_blocks_at_slot(&self, slot: Slot) -> Vec<VerifiedBlock> {
361 let mut blocks = vec![];
362 for (_block_ref, block) in self.blocks.range((
363 Included(BlockRef::new(slot.round, slot.authority, BlockDigest::MIN)),
364 Included(BlockRef::new(slot.round, slot.authority, BlockDigest::MAX)),
365 )) {
366 blocks.push(block.clone())
367 }
368 blocks
369 }
370
371 pub fn genesis_block_refs(&self) -> Vec<BlockRef> {
372 self.genesis.keys().cloned().collect()
373 }
374}
375
376pub struct LayerBuilder<'a> {
378 dag_builder: &'a mut DagBuilder,
379
380 start_round: Round,
381 end_round: Option<Round>,
382
383 specified_authorities: Option<Vec<AuthorityIndex>>,
386 num_transactions: u32,
388 rejected_transactions_pct: u8,
390 rejected_transactions_seed: u64,
391 equivocations: usize,
393 skip_block: bool,
395 skip_ancestor_links: Option<Vec<AuthorityIndex>>,
397 no_leader_link: bool,
399 override_last_ancestors: bool,
401
402 no_leader_block: bool,
404 specified_leader_link_offsets: Option<Vec<u32>>,
406 specified_leader_block_offsets: Option<Vec<u32>>,
407 leader_round: Option<Round>,
408
409 fully_linked_ancestors: bool,
411 min_ancestor_links: bool,
414 min_ancestor_links_random_seed: Option<u64>,
415 random_weak_links: bool,
417 random_weak_links_random_seed: Option<u64>,
418
419 ancestors: Vec<BlockRef>,
421 specified_ancestors: Vec<BlockRef>,
423
424 timestamps: Vec<BlockTimestampMs>,
426
427 blocks: Vec<VerifiedBlock>,
429}
430
431#[allow(unused)]
432impl<'a> LayerBuilder<'a> {
433 fn new(dag_builder: &'a mut DagBuilder, start_round: Round) -> Self {
434 assert!(start_round > 0, "genesis round is created by default");
435 let ancestors = dag_builder.last_ancestors.clone();
436 Self {
437 dag_builder,
438 start_round,
439 end_round: None,
440 specified_authorities: None,
441 num_transactions: 0,
442 rejected_transactions_pct: 0,
443 rejected_transactions_seed: 0,
444 equivocations: 0,
445 skip_block: false,
446 skip_ancestor_links: None,
447 override_last_ancestors: false,
448 no_leader_link: false,
449 no_leader_block: false,
450 specified_leader_link_offsets: None,
451 specified_leader_block_offsets: None,
452 leader_round: None,
453 fully_linked_ancestors: true,
454 min_ancestor_links: false,
455 min_ancestor_links_random_seed: None,
456 random_weak_links: false,
457 random_weak_links_random_seed: None,
458 ancestors,
459 specified_ancestors: vec![],
460 timestamps: vec![],
461 blocks: vec![],
462 }
463 }
464
465 pub fn override_last_ancestors(mut self, ancestors: Vec<BlockRef>) -> Self {
471 self.specified_ancestors = ancestors;
472 self.override_last_ancestors = true;
473 self.build()
474 }
475
476 pub fn min_ancestor_links(mut self, include_leader: bool, seed: Option<u64>) -> Self {
480 self.min_ancestor_links = true;
481 self.min_ancestor_links_random_seed = seed;
482 if include_leader {
483 self.leader_round = Some(self.ancestors.iter().max_by_key(|b| b.round).unwrap().round);
484 }
485 self.fully_linked_ancestors = false;
486 self.build()
487 }
488
489 pub fn skip_ancestor_links(mut self, ancestors_to_skip: Vec<AuthorityIndex>) -> Self {
493 assert!(self.specified_authorities.is_some());
495 self.skip_ancestor_links = Some(ancestors_to_skip);
496 self.fully_linked_ancestors = false;
497 self.build()
498 }
499
500 pub fn random_weak_links(mut self, seed: Option<u64>) -> Self {
502 self.random_weak_links = true;
503 self.random_weak_links_random_seed = seed;
504 self
505 }
506
507 pub fn no_leader_block(mut self, specified_leader_offsets: Vec<u32>) -> Self {
511 self.no_leader_block = true;
512 self.specified_leader_block_offsets = Some(specified_leader_offsets);
513 self
514 }
515
516 pub fn no_leader_link(
521 mut self,
522 leader_round: Round,
523 specified_leader_offsets: Vec<u32>,
524 ) -> Self {
525 self.no_leader_link = true;
526 self.specified_leader_link_offsets = Some(specified_leader_offsets);
527 self.leader_round = Some(leader_round);
528 self.fully_linked_ancestors = false;
529 self.build()
530 }
531
532 pub fn authorities(mut self, authorities: Vec<AuthorityIndex>) -> Self {
533 assert!(
534 self.specified_authorities.is_none(),
535 "Specified authorities already set"
536 );
537 self.specified_authorities = Some(authorities);
538 self
539 }
540
541 pub fn num_transactions(mut self, num_transactions: u32) -> Self {
543 self.num_transactions = num_transactions;
544 self
545 }
546
547 pub fn rejected_transactions_pct(mut self, pct: u8, seed: Option<u64>) -> Self {
548 self.rejected_transactions_pct = pct;
549 self.rejected_transactions_seed = if let Some(seed) = seed {
550 seed
551 } else {
552 thread_rng().r#gen()
553 };
554 self
555 }
556
557 pub fn equivocate(mut self, equivocations: usize) -> Self {
559 assert!(self.specified_authorities.is_some());
561 self.equivocations = equivocations;
562 self
563 }
564
565 pub fn skip_block(mut self) -> Self {
567 assert!(self.specified_authorities.is_some());
569 self.skip_block = true;
570 self
571 }
572
573 pub fn with_timestamps(mut self, timestamps: Vec<BlockTimestampMs>) -> Self {
574 assert!(self.specified_authorities.is_some());
576 assert_eq!(
577 self.specified_authorities.as_ref().unwrap().len(),
578 timestamps.len(),
579 "Timestamps should be provided for each specified authority"
580 );
581 self.timestamps = timestamps;
582 self
583 }
584
585 pub fn build(mut self) -> Self {
587 for round in self.start_round..=self.end_round.unwrap_or(self.start_round) {
588 tracing::debug!("BUILDING LAYER ROUND {round}...");
589
590 let authorities = if self.specified_authorities.is_some() {
591 self.specified_authorities.clone().unwrap()
592 } else {
593 self.dag_builder
594 .context
595 .committee
596 .authorities()
597 .map(|x| x.0)
598 .collect()
599 };
600
601 let mut connections = if self.override_last_ancestors {
604 self.configure_specifed_ancestors()
605 } else if self.fully_linked_ancestors {
606 self.configure_fully_linked_ancestors(round)
607 } else if self.min_ancestor_links {
608 self.configure_min_parent_links(round)
609 } else if self.no_leader_link {
610 self.configure_no_leader_links(authorities.clone(), round)
611 } else if self.skip_ancestor_links.is_some() {
612 self.configure_skipped_ancestor_links(
613 authorities,
614 self.skip_ancestor_links.clone().unwrap(),
615 )
616 } else {
617 vec![]
618 };
619
620 if self.random_weak_links {
621 connections.append(&mut self.configure_random_weak_links());
622 }
623
624 self.create_blocks(round, connections);
625 }
626
627 self.dag_builder.last_ancestors = self.ancestors.clone();
628 self
629 }
630
631 pub fn persist_layers(&self, dag_state: Arc<RwLock<DagState>>) {
632 assert!(
633 !self.blocks.is_empty(),
634 "Called to persist layers although no blocks have been created. Make sure you have called build before."
635 );
636 dag_state.write().accept_blocks(self.blocks.clone());
637 }
638
639 pub fn configure_min_parent_links(
641 &mut self,
642 round: Round,
643 ) -> Vec<(AuthorityIndex, Vec<BlockRef>)> {
644 let quorum_threshold = self.dag_builder.context.committee.quorum_threshold() as usize;
645 let mut authorities: Vec<AuthorityIndex> = self
646 .dag_builder
647 .context
648 .committee
649 .authorities()
650 .map(|authority| authority.0)
651 .collect();
652
653 let mut rng = match self.min_ancestor_links_random_seed {
654 Some(s) => StdRng::seed_from_u64(s),
655 None => StdRng::from_entropy(),
656 };
657
658 let mut authorities_to_shuffle = authorities.clone();
659
660 let mut leaders = vec![];
661 if let Some(leader_round) = self.leader_round {
662 let leader_offsets = (0..self.dag_builder.number_of_leaders).collect::<Vec<_>>();
663
664 for leader_offset in leader_offsets {
665 leaders.push(
666 self.dag_builder
667 .leader_schedule
668 .elect_leader(leader_round, leader_offset),
669 );
670 }
671 }
672
673 authorities
674 .iter()
675 .map(|authority| {
676 authorities_to_shuffle.shuffle(&mut rng);
677
678 let min_ancestors: HashSet<AuthorityIndex> = authorities_to_shuffle
680 .iter()
681 .take(quorum_threshold)
682 .cloned()
683 .collect();
684
685 (
686 *authority,
687 self.ancestors
688 .iter()
689 .filter(|a| {
690 leaders.contains(&a.author)
691 || min_ancestors.contains(&a.author)
692 || a.round != round
693 })
694 .cloned()
695 .collect::<Vec<BlockRef>>(),
696 )
697 })
698 .collect()
699 }
700
701 fn configure_random_weak_links(&mut self) -> Vec<(AuthorityIndex, Vec<BlockRef>)> {
703 unimplemented!("configure_random_weak_links");
704 }
705
706 fn configure_no_leader_links(
708 &mut self,
709 authorities: Vec<AuthorityIndex>,
710 round: Round,
711 ) -> Vec<(AuthorityIndex, Vec<BlockRef>)> {
712 let mut missing_leaders = Vec::new();
713 let mut specified_leader_offsets = self
714 .specified_leader_link_offsets
715 .clone()
716 .expect("specified_leader_offsets should be set");
717 let leader_round = self.leader_round.expect("leader round should be set");
718
719 if specified_leader_offsets.is_empty() {
722 specified_leader_offsets.extend(0..self.dag_builder.number_of_leaders);
723 }
724
725 for leader_offset in specified_leader_offsets {
726 missing_leaders.push(
727 self.dag_builder
728 .leader_schedule
729 .elect_leader(leader_round, leader_offset),
730 );
731 }
732
733 self.configure_skipped_ancestor_links(authorities, missing_leaders)
734 }
735
736 fn configure_specifed_ancestors(&mut self) -> Vec<(AuthorityIndex, Vec<BlockRef>)> {
737 self.dag_builder
738 .context
739 .committee
740 .authorities()
741 .map(|authority| (authority.0, self.specified_ancestors.clone()))
742 .collect::<Vec<_>>()
743 }
744
745 fn configure_fully_linked_ancestors(
746 &mut self,
747 round: Round,
748 ) -> Vec<(AuthorityIndex, Vec<BlockRef>)> {
749 self.dag_builder
750 .context
751 .committee
752 .authorities()
753 .map(|authority| {
754 (
755 authority.0,
756 self.ancestors
758 .clone()
759 .into_iter()
760 .filter(|a| a.round != round)
761 .collect::<Vec<_>>(),
762 )
763 })
764 .collect::<Vec<_>>()
765 }
766
767 fn configure_skipped_ancestor_links(
768 &mut self,
769 authorities: Vec<AuthorityIndex>,
770 ancestors_to_skip: Vec<AuthorityIndex>,
771 ) -> Vec<(AuthorityIndex, Vec<BlockRef>)> {
772 let filtered_ancestors = self
773 .ancestors
774 .clone()
775 .into_iter()
776 .filter(|ancestor| !ancestors_to_skip.contains(&ancestor.author))
777 .collect::<Vec<_>>();
778 authorities
779 .into_iter()
780 .map(|authority| (authority, filtered_ancestors.clone()))
781 .collect::<Vec<_>>()
782 }
783
784 fn create_blocks(&mut self, round: Round, connections: Vec<(AuthorityIndex, Vec<BlockRef>)>) {
787 let mut references = Vec::new();
788 let mut reject_rng =
789 StdRng::seed_from_u64(self.rejected_transactions_seed ^ (round as u64));
790 for (authority, ancestors) in connections {
791 if self.should_skip_block(round, authority) {
792 continue;
793 };
794 let transactions = (0..self.num_transactions)
795 .map(|_| Transaction::new(vec![1_u8; 16]))
796 .collect::<Vec<_>>();
797 let num_blocks = self.num_blocks_to_create(authority);
798 for num_block in 0..num_blocks {
799 let mut votes = vec![];
800 if self.rejected_transactions_pct > 0 {
801 for ancestor in &ancestors {
802 let mut rejects = vec![];
803 for i in 0..self.num_transactions {
804 if reject_rng.gen_range(1..=100) <= self.rejected_transactions_pct {
805 rejects.push(i as TransactionIndex);
806 }
807 }
808 if !rejects.is_empty() {
809 votes.push(BlockTransactionVotes {
810 block_ref: *ancestor,
811 rejects,
812 });
813 }
814 }
815 }
816 let timestamp = self.block_timestamp(authority, round, num_block);
817 let block = VerifiedBlock::new_for_test(
818 TestBlock::new(round, authority.value() as u32)
819 .set_transactions(transactions.clone())
820 .set_transaction_votes(votes)
821 .set_ancestors(ancestors.clone())
822 .set_timestamp_ms(timestamp)
823 .build(),
824 );
825 references.push(block.reference());
826 self.dag_builder
827 .blocks
828 .insert(block.reference(), block.clone());
829 self.blocks.push(block);
830 }
831 }
832 self.ancestors = references;
833 }
834
835 fn num_blocks_to_create(&self, authority: AuthorityIndex) -> u32 {
836 if self.specified_authorities.is_some()
837 && self
838 .specified_authorities
839 .clone()
840 .unwrap()
841 .contains(&authority)
842 {
843 1 + self.equivocations as u32
845 } else {
846 1
847 }
848 }
849
850 fn block_timestamp(
851 &self,
852 authority: AuthorityIndex,
853 round: Round,
854 num_block: u32,
855 ) -> BlockTimestampMs {
856 if self.specified_authorities.is_some() && !self.timestamps.is_empty() {
857 let specified_authorities = self.specified_authorities.as_ref().unwrap();
858
859 if let Some(position) = specified_authorities.iter().position(|&x| x == authority) {
860 return self.timestamps[position] + (round + num_block) as u64;
861 }
862 }
863 let author = authority.value() as u32;
864 let base_ts = round as BlockTimestampMs * 1000;
865 base_ts + (author + round + num_block) as u64
866 }
867
868 fn should_skip_block(&self, round: Round, authority: AuthorityIndex) -> bool {
869 if self.skip_block
872 && self
873 .specified_authorities
874 .clone()
875 .unwrap()
876 .contains(&authority)
877 {
878 return true;
879 }
880 if self.no_leader_block {
881 let mut specified_leader_offsets = self
882 .specified_leader_block_offsets
883 .clone()
884 .expect("specified_leader_block_offsets should be set");
885
886 if specified_leader_offsets.is_empty() {
889 specified_leader_offsets.extend(0..self.dag_builder.number_of_leaders);
890 }
891
892 for leader_offset in specified_leader_offsets {
893 let leader = self
894 .dag_builder
895 .leader_schedule
896 .elect_leader(round, leader_offset);
897
898 if leader == authority {
899 return true;
900 }
901 }
902 }
903 false
904 }
905}