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 true,
250 );
251
252 self.committed_sub_dags.push((sub_dag, commit));
253 }
254
255 self.committed_sub_dags
256 .clone()
257 .into_iter()
258 .filter(|(sub_dag, _)| leader_rounds.contains(&sub_dag.leader.round))
259 .collect()
260 }
261
262 #[cfg(test)]
263 pub(crate) fn get_sub_dag_and_certified_commits(
264 &mut self,
265 leader_rounds: RangeInclusive<Round>,
266 ) -> Vec<(CommittedSubDag, CertifiedCommit)> {
267 let commits = self.get_sub_dag_and_commits(leader_rounds);
268 commits
269 .into_iter()
270 .map(|(sub_dag, commit)| {
271 let certified_commit =
272 CertifiedCommit::new_certified(commit, sub_dag.blocks.clone());
273 (sub_dag, certified_commit)
274 })
275 .collect()
276 }
277
278 pub fn leader_blocks(&self, rounds: RangeInclusive<Round>) -> Vec<Option<VerifiedBlock>> {
279 assert!(
280 !self.blocks.is_empty(),
281 "No blocks have been created, please make sure that you have called build method"
282 );
283 rounds
284 .into_iter()
285 .map(|round| self.leader_block(round))
286 .collect()
287 }
288
289 pub fn leader_block(&self, round: Round) -> Option<VerifiedBlock> {
290 assert!(
291 !self.blocks.is_empty(),
292 "No blocks have been created, please make sure that you have called build method"
293 );
294 self.blocks
295 .iter()
296 .find(|(block_ref, _block)| {
297 block_ref.round == round
298 && block_ref.author == self.leader_schedule.elect_leader(round, 0)
299 })
300 .map(|(_block_ref, block)| block.clone())
301 }
302
303 pub fn layer(&mut self, round: Round) -> LayerBuilder<'_> {
304 LayerBuilder::new(self, round)
305 }
306
307 pub fn layers(&mut self, rounds: RangeInclusive<Round>) -> LayerBuilder<'_> {
308 let mut builder = LayerBuilder::new(self, *rounds.start());
309 builder.end_round = Some(*rounds.end());
310 builder
311 }
312
313 pub fn persist_all_blocks(&self, dag_state: Arc<RwLock<DagState>>) {
314 dag_state
315 .write()
316 .accept_blocks(self.blocks.values().cloned().collect());
317 }
318
319 pub fn print(&self) {
320 let mut dag_str = "DAG {\n".to_string();
321
322 let mut round = 0;
323 for block in self.blocks.values() {
324 if block.round() > round {
325 round = block.round();
326 dag_str.push_str(&format!("Round {round} : \n"));
327 }
328 dag_str.push_str(&format!(" Block {block:#?}\n"));
329 }
330 dag_str.push_str("}\n");
331
332 tracing::info!("{dag_str}");
333 }
334
335 pub fn layer_with_connections(
340 &mut self,
341 connections: Vec<(AuthorityIndex, Vec<BlockRef>)>,
342 round: Round,
343 ) {
344 let mut references = Vec::new();
345 for (authority, ancestors) in connections {
346 let author = authority.value() as u32;
347 let base_ts = round as BlockTimestampMs * 1000;
348 let block = VerifiedBlock::new_for_test(
349 TestBlock::new(round, author)
350 .set_ancestors(ancestors)
351 .set_timestamp_ms(base_ts + author as u64)
352 .build(),
353 );
354 references.push(block.reference());
355 self.blocks.insert(block.reference(), block.clone());
356 }
357 self.last_ancestors = references;
358 }
359
360 pub fn get_uncommitted_blocks_at_slot(&self, slot: Slot) -> Vec<VerifiedBlock> {
362 let mut blocks = vec![];
363 for (_block_ref, block) in self.blocks.range((
364 Included(BlockRef::new(slot.round, slot.authority, BlockDigest::MIN)),
365 Included(BlockRef::new(slot.round, slot.authority, BlockDigest::MAX)),
366 )) {
367 blocks.push(block.clone())
368 }
369 blocks
370 }
371
372 pub fn genesis_block_refs(&self) -> Vec<BlockRef> {
373 self.genesis.keys().cloned().collect()
374 }
375}
376
377pub struct LayerBuilder<'a> {
379 dag_builder: &'a mut DagBuilder,
380
381 start_round: Round,
382 end_round: Option<Round>,
383
384 specified_authorities: Option<Vec<AuthorityIndex>>,
387 num_transactions: u32,
389 rejected_transactions_pct: u8,
391 rejected_transactions_seed: u64,
392 equivocations: usize,
394 skip_block: bool,
396 skip_ancestor_links: Option<Vec<AuthorityIndex>>,
398 no_leader_link: bool,
400 override_last_ancestors: bool,
402
403 no_leader_block: bool,
405 specified_leader_link_offsets: Option<Vec<u32>>,
407 specified_leader_block_offsets: Option<Vec<u32>>,
408 leader_round: Option<Round>,
409
410 fully_linked_ancestors: bool,
412 min_ancestor_links: bool,
415 min_ancestor_links_random_seed: Option<u64>,
416 random_weak_links: bool,
418 random_weak_links_random_seed: Option<u64>,
419
420 ancestors: Vec<BlockRef>,
422 specified_ancestors: Vec<BlockRef>,
424
425 timestamps: Vec<BlockTimestampMs>,
427
428 blocks: Vec<VerifiedBlock>,
430}
431
432#[allow(unused)]
433impl<'a> LayerBuilder<'a> {
434 fn new(dag_builder: &'a mut DagBuilder, start_round: Round) -> Self {
435 assert!(start_round > 0, "genesis round is created by default");
436 let ancestors = dag_builder.last_ancestors.clone();
437 Self {
438 dag_builder,
439 start_round,
440 end_round: None,
441 specified_authorities: None,
442 num_transactions: 0,
443 rejected_transactions_pct: 0,
444 rejected_transactions_seed: 0,
445 equivocations: 0,
446 skip_block: false,
447 skip_ancestor_links: None,
448 override_last_ancestors: false,
449 no_leader_link: false,
450 no_leader_block: false,
451 specified_leader_link_offsets: None,
452 specified_leader_block_offsets: None,
453 leader_round: None,
454 fully_linked_ancestors: true,
455 min_ancestor_links: false,
456 min_ancestor_links_random_seed: None,
457 random_weak_links: false,
458 random_weak_links_random_seed: None,
459 ancestors,
460 specified_ancestors: vec![],
461 timestamps: vec![],
462 blocks: vec![],
463 }
464 }
465
466 pub fn override_last_ancestors(mut self, ancestors: Vec<BlockRef>) -> Self {
472 self.specified_ancestors = ancestors;
473 self.override_last_ancestors = true;
474 self.build()
475 }
476
477 pub fn min_ancestor_links(mut self, include_leader: bool, seed: Option<u64>) -> Self {
481 self.min_ancestor_links = true;
482 self.min_ancestor_links_random_seed = seed;
483 if include_leader {
484 self.leader_round = Some(self.ancestors.iter().max_by_key(|b| b.round).unwrap().round);
485 }
486 self.fully_linked_ancestors = false;
487 self.build()
488 }
489
490 pub fn skip_ancestor_links(mut self, ancestors_to_skip: Vec<AuthorityIndex>) -> Self {
494 assert!(self.specified_authorities.is_some());
496 self.skip_ancestor_links = Some(ancestors_to_skip);
497 self.fully_linked_ancestors = false;
498 self.build()
499 }
500
501 pub fn random_weak_links(mut self, seed: Option<u64>) -> Self {
503 self.random_weak_links = true;
504 self.random_weak_links_random_seed = seed;
505 self
506 }
507
508 pub fn no_leader_block(mut self, specified_leader_offsets: Vec<u32>) -> Self {
512 self.no_leader_block = true;
513 self.specified_leader_block_offsets = Some(specified_leader_offsets);
514 self
515 }
516
517 pub fn no_leader_link(
522 mut self,
523 leader_round: Round,
524 specified_leader_offsets: Vec<u32>,
525 ) -> Self {
526 self.no_leader_link = true;
527 self.specified_leader_link_offsets = Some(specified_leader_offsets);
528 self.leader_round = Some(leader_round);
529 self.fully_linked_ancestors = false;
530 self.build()
531 }
532
533 pub fn authorities(mut self, authorities: Vec<AuthorityIndex>) -> Self {
534 assert!(
535 self.specified_authorities.is_none(),
536 "Specified authorities already set"
537 );
538 self.specified_authorities = Some(authorities);
539 self
540 }
541
542 pub fn num_transactions(mut self, num_transactions: u32) -> Self {
544 self.num_transactions = num_transactions;
545 self
546 }
547
548 pub fn rejected_transactions_pct(mut self, pct: u8, seed: Option<u64>) -> Self {
549 self.rejected_transactions_pct = pct;
550 self.rejected_transactions_seed = if let Some(seed) = seed {
551 seed
552 } else {
553 thread_rng().r#gen()
554 };
555 self
556 }
557
558 pub fn equivocate(mut self, equivocations: usize) -> Self {
560 assert!(self.specified_authorities.is_some());
562 self.equivocations = equivocations;
563 self
564 }
565
566 pub fn skip_block(mut self) -> Self {
568 assert!(self.specified_authorities.is_some());
570 self.skip_block = true;
571 self
572 }
573
574 pub fn with_timestamps(mut self, timestamps: Vec<BlockTimestampMs>) -> Self {
575 assert!(self.specified_authorities.is_some());
577 assert_eq!(
578 self.specified_authorities.as_ref().unwrap().len(),
579 timestamps.len(),
580 "Timestamps should be provided for each specified authority"
581 );
582 self.timestamps = timestamps;
583 self
584 }
585
586 pub fn build(mut self) -> Self {
588 for round in self.start_round..=self.end_round.unwrap_or(self.start_round) {
589 tracing::debug!("BUILDING LAYER ROUND {round}...");
590
591 let authorities = if self.specified_authorities.is_some() {
592 self.specified_authorities.clone().unwrap()
593 } else {
594 self.dag_builder
595 .context
596 .committee
597 .authorities()
598 .map(|x| x.0)
599 .collect()
600 };
601
602 let mut connections = if self.override_last_ancestors {
605 self.configure_specifed_ancestors()
606 } else if self.fully_linked_ancestors {
607 self.configure_fully_linked_ancestors(round)
608 } else if self.min_ancestor_links {
609 self.configure_min_parent_links(round)
610 } else if self.no_leader_link {
611 self.configure_no_leader_links(authorities.clone(), round)
612 } else if self.skip_ancestor_links.is_some() {
613 self.configure_skipped_ancestor_links(
614 authorities,
615 self.skip_ancestor_links.clone().unwrap(),
616 )
617 } else {
618 vec![]
619 };
620
621 if self.random_weak_links {
622 connections.append(&mut self.configure_random_weak_links());
623 }
624
625 self.create_blocks(round, connections);
626 }
627
628 self.dag_builder.last_ancestors = self.ancestors.clone();
629 self
630 }
631
632 pub fn persist_layers(&self, dag_state: Arc<RwLock<DagState>>) {
633 assert!(
634 !self.blocks.is_empty(),
635 "Called to persist layers although no blocks have been created. Make sure you have called build before."
636 );
637 dag_state.write().accept_blocks(self.blocks.clone());
638 }
639
640 pub fn configure_min_parent_links(
642 &mut self,
643 round: Round,
644 ) -> Vec<(AuthorityIndex, Vec<BlockRef>)> {
645 let quorum_threshold = self.dag_builder.context.committee.quorum_threshold() as usize;
646 let mut authorities: Vec<AuthorityIndex> = self
647 .dag_builder
648 .context
649 .committee
650 .authorities()
651 .map(|authority| authority.0)
652 .collect();
653
654 let mut rng = match self.min_ancestor_links_random_seed {
655 Some(s) => StdRng::seed_from_u64(s),
656 None => StdRng::from_entropy(),
657 };
658
659 let mut authorities_to_shuffle = authorities.clone();
660
661 let mut leaders = vec![];
662 if let Some(leader_round) = self.leader_round {
663 let leader_offsets = (0..self.dag_builder.number_of_leaders).collect::<Vec<_>>();
664
665 for leader_offset in leader_offsets {
666 leaders.push(
667 self.dag_builder
668 .leader_schedule
669 .elect_leader(leader_round, leader_offset),
670 );
671 }
672 }
673
674 authorities
675 .iter()
676 .map(|authority| {
677 authorities_to_shuffle.shuffle(&mut rng);
678
679 let min_ancestors: HashSet<AuthorityIndex> = authorities_to_shuffle
681 .iter()
682 .take(quorum_threshold)
683 .cloned()
684 .collect();
685
686 (
687 *authority,
688 self.ancestors
689 .iter()
690 .filter(|a| {
691 leaders.contains(&a.author)
692 || min_ancestors.contains(&a.author)
693 || a.round != round
694 })
695 .cloned()
696 .collect::<Vec<BlockRef>>(),
697 )
698 })
699 .collect()
700 }
701
702 fn configure_random_weak_links(&mut self) -> Vec<(AuthorityIndex, Vec<BlockRef>)> {
704 unimplemented!("configure_random_weak_links");
705 }
706
707 fn configure_no_leader_links(
709 &mut self,
710 authorities: Vec<AuthorityIndex>,
711 round: Round,
712 ) -> Vec<(AuthorityIndex, Vec<BlockRef>)> {
713 let mut missing_leaders = Vec::new();
714 let mut specified_leader_offsets = self
715 .specified_leader_link_offsets
716 .clone()
717 .expect("specified_leader_offsets should be set");
718 let leader_round = self.leader_round.expect("leader round should be set");
719
720 if specified_leader_offsets.is_empty() {
723 specified_leader_offsets.extend(0..self.dag_builder.number_of_leaders);
724 }
725
726 for leader_offset in specified_leader_offsets {
727 missing_leaders.push(
728 self.dag_builder
729 .leader_schedule
730 .elect_leader(leader_round, leader_offset),
731 );
732 }
733
734 self.configure_skipped_ancestor_links(authorities, missing_leaders)
735 }
736
737 fn configure_specifed_ancestors(&mut self) -> Vec<(AuthorityIndex, Vec<BlockRef>)> {
738 self.dag_builder
739 .context
740 .committee
741 .authorities()
742 .map(|authority| (authority.0, self.specified_ancestors.clone()))
743 .collect::<Vec<_>>()
744 }
745
746 fn configure_fully_linked_ancestors(
747 &mut self,
748 round: Round,
749 ) -> Vec<(AuthorityIndex, Vec<BlockRef>)> {
750 self.dag_builder
751 .context
752 .committee
753 .authorities()
754 .map(|authority| {
755 (
756 authority.0,
757 self.ancestors
759 .clone()
760 .into_iter()
761 .filter(|a| a.round != round)
762 .collect::<Vec<_>>(),
763 )
764 })
765 .collect::<Vec<_>>()
766 }
767
768 fn configure_skipped_ancestor_links(
769 &mut self,
770 authorities: Vec<AuthorityIndex>,
771 ancestors_to_skip: Vec<AuthorityIndex>,
772 ) -> Vec<(AuthorityIndex, Vec<BlockRef>)> {
773 let filtered_ancestors = self
774 .ancestors
775 .clone()
776 .into_iter()
777 .filter(|ancestor| !ancestors_to_skip.contains(&ancestor.author))
778 .collect::<Vec<_>>();
779 authorities
780 .into_iter()
781 .map(|authority| (authority, filtered_ancestors.clone()))
782 .collect::<Vec<_>>()
783 }
784
785 fn create_blocks(&mut self, round: Round, connections: Vec<(AuthorityIndex, Vec<BlockRef>)>) {
788 let mut references = Vec::new();
789 let mut reject_rng =
790 StdRng::seed_from_u64(self.rejected_transactions_seed ^ (round as u64));
791 for (authority, ancestors) in connections {
792 if self.should_skip_block(round, authority) {
793 continue;
794 };
795 let transactions = (0..self.num_transactions)
796 .map(|_| Transaction::new(vec![1_u8; 16]))
797 .collect::<Vec<_>>();
798 let num_blocks = self.num_blocks_to_create(authority);
799 for num_block in 0..num_blocks {
800 let mut votes = vec![];
801 if self.rejected_transactions_pct > 0 {
802 for ancestor in &ancestors {
803 let mut rejects = vec![];
804 for i in 0..self.num_transactions {
805 if reject_rng.gen_range(1..=100) <= self.rejected_transactions_pct {
806 rejects.push(i as TransactionIndex);
807 }
808 }
809 if !rejects.is_empty() {
810 votes.push(BlockTransactionVotes {
811 block_ref: *ancestor,
812 rejects,
813 });
814 }
815 }
816 }
817 let timestamp = self.block_timestamp(authority, round, num_block);
818 let block = VerifiedBlock::new_for_test(
819 TestBlock::new(round, authority.value() as u32)
820 .set_transactions(transactions.clone())
821 .set_transaction_votes(votes)
822 .set_ancestors(ancestors.clone())
823 .set_timestamp_ms(timestamp)
824 .build(),
825 );
826 references.push(block.reference());
827 self.dag_builder
828 .blocks
829 .insert(block.reference(), block.clone());
830 self.blocks.push(block);
831 }
832 }
833 self.ancestors = references;
834 }
835
836 fn num_blocks_to_create(&self, authority: AuthorityIndex) -> u32 {
837 if self.specified_authorities.is_some()
838 && self
839 .specified_authorities
840 .clone()
841 .unwrap()
842 .contains(&authority)
843 {
844 1 + self.equivocations as u32
846 } else {
847 1
848 }
849 }
850
851 fn block_timestamp(
852 &self,
853 authority: AuthorityIndex,
854 round: Round,
855 num_block: u32,
856 ) -> BlockTimestampMs {
857 if self.specified_authorities.is_some() && !self.timestamps.is_empty() {
858 let specified_authorities = self.specified_authorities.as_ref().unwrap();
859
860 if let Some(position) = specified_authorities.iter().position(|&x| x == authority) {
861 return self.timestamps[position] + (round + num_block) as u64;
862 }
863 }
864 let author = authority.value() as u32;
865 let base_ts = round as BlockTimestampMs * 1000;
866 base_ts + (author + round + num_block) as u64
867 }
868
869 fn should_skip_block(&self, round: Round, authority: AuthorityIndex) -> bool {
870 if self.skip_block
873 && self
874 .specified_authorities
875 .clone()
876 .unwrap()
877 .contains(&authority)
878 {
879 return true;
880 }
881 if self.no_leader_block {
882 let mut specified_leader_offsets = self
883 .specified_leader_block_offsets
884 .clone()
885 .expect("specified_leader_block_offsets should be set");
886
887 if specified_leader_offsets.is_empty() {
890 specified_leader_offsets.extend(0..self.dag_builder.number_of_leaders);
891 }
892
893 for leader_offset in specified_leader_offsets {
894 let leader = self
895 .dag_builder
896 .leader_schedule
897 .elect_leader(round, leader_offset);
898
899 if leader == authority {
900 return true;
901 }
902 }
903 }
904 false
905 }
906}