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
431impl<'a> LayerBuilder<'a> {
432 fn new(dag_builder: &'a mut DagBuilder, start_round: Round) -> Self {
433 assert!(start_round > 0, "genesis round is created by default");
434 let ancestors = dag_builder.last_ancestors.clone();
435 Self {
436 dag_builder,
437 start_round,
438 end_round: None,
439 specified_authorities: None,
440 num_transactions: 0,
441 rejected_transactions_pct: 0,
442 rejected_transactions_seed: 0,
443 equivocations: 0,
444 skip_block: false,
445 skip_ancestor_links: None,
446 override_last_ancestors: false,
447 no_leader_link: false,
448 no_leader_block: false,
449 specified_leader_link_offsets: None,
450 specified_leader_block_offsets: None,
451 leader_round: None,
452 fully_linked_ancestors: true,
453 min_ancestor_links: false,
454 min_ancestor_links_random_seed: None,
455 random_weak_links: false,
456 random_weak_links_random_seed: None,
457 ancestors,
458 specified_ancestors: vec![],
459 timestamps: vec![],
460 blocks: vec![],
461 }
462 }
463
464 pub fn override_last_ancestors(mut self, ancestors: Vec<BlockRef>) -> Self {
470 self.specified_ancestors = ancestors;
471 self.override_last_ancestors = true;
472 self.build()
473 }
474
475 pub fn min_ancestor_links(mut self, include_leader: bool, seed: Option<u64>) -> Self {
479 self.min_ancestor_links = true;
480 self.min_ancestor_links_random_seed = seed;
481 if include_leader {
482 self.leader_round = Some(self.ancestors.iter().max_by_key(|b| b.round).unwrap().round);
483 }
484 self.fully_linked_ancestors = false;
485 self.build()
486 }
487
488 pub fn skip_ancestor_links(mut self, ancestors_to_skip: Vec<AuthorityIndex>) -> Self {
492 assert!(self.specified_authorities.is_some());
494 self.skip_ancestor_links = Some(ancestors_to_skip);
495 self.fully_linked_ancestors = false;
496 self.build()
497 }
498
499 pub fn random_weak_links(mut self, seed: Option<u64>) -> Self {
501 self.random_weak_links = true;
502 self.random_weak_links_random_seed = seed;
503 self
504 }
505
506 pub fn no_leader_block(mut self, specified_leader_offsets: Vec<u32>) -> Self {
510 self.no_leader_block = true;
511 self.specified_leader_block_offsets = Some(specified_leader_offsets);
512 self
513 }
514
515 pub fn no_leader_link(
520 mut self,
521 leader_round: Round,
522 specified_leader_offsets: Vec<u32>,
523 ) -> Self {
524 self.no_leader_link = true;
525 self.specified_leader_link_offsets = Some(specified_leader_offsets);
526 self.leader_round = Some(leader_round);
527 self.fully_linked_ancestors = false;
528 self.build()
529 }
530
531 pub fn authorities(mut self, authorities: Vec<AuthorityIndex>) -> Self {
532 assert!(
533 self.specified_authorities.is_none(),
534 "Specified authorities already set"
535 );
536 self.specified_authorities = Some(authorities);
537 self
538 }
539
540 pub fn num_transactions(mut self, num_transactions: u32) -> Self {
542 self.num_transactions = num_transactions;
543 self
544 }
545
546 pub fn rejected_transactions_pct(mut self, pct: u8, seed: Option<u64>) -> Self {
547 self.rejected_transactions_pct = pct;
548 self.rejected_transactions_seed = if let Some(seed) = seed {
549 seed
550 } else {
551 thread_rng().r#gen()
552 };
553 self
554 }
555
556 pub fn equivocate(mut self, equivocations: usize) -> Self {
558 assert!(self.specified_authorities.is_some());
560 self.equivocations = equivocations;
561 self
562 }
563
564 pub fn skip_block(mut self) -> Self {
566 assert!(self.specified_authorities.is_some());
568 self.skip_block = true;
569 self
570 }
571
572 pub fn with_timestamps(mut self, timestamps: Vec<BlockTimestampMs>) -> Self {
573 assert!(self.specified_authorities.is_some());
575 assert_eq!(
576 self.specified_authorities.as_ref().unwrap().len(),
577 timestamps.len(),
578 "Timestamps should be provided for each specified authority"
579 );
580 self.timestamps = timestamps;
581 self
582 }
583
584 pub fn build(mut self) -> Self {
586 for round in self.start_round..=self.end_round.unwrap_or(self.start_round) {
587 tracing::debug!("BUILDING LAYER ROUND {round}...");
588
589 let authorities = if self.specified_authorities.is_some() {
590 self.specified_authorities.clone().unwrap()
591 } else {
592 self.dag_builder
593 .context
594 .committee
595 .authorities()
596 .map(|x| x.0)
597 .collect()
598 };
599
600 let mut connections = if self.override_last_ancestors {
603 self.configure_specifed_ancestors()
604 } else if self.fully_linked_ancestors {
605 self.configure_fully_linked_ancestors(round)
606 } else if self.min_ancestor_links {
607 self.configure_min_parent_links(round)
608 } else if self.no_leader_link {
609 self.configure_no_leader_links(authorities.clone(), round)
610 } else if self.skip_ancestor_links.is_some() {
611 self.configure_skipped_ancestor_links(
612 authorities,
613 self.skip_ancestor_links.clone().unwrap(),
614 )
615 } else {
616 vec![]
617 };
618
619 if self.random_weak_links {
620 connections.append(&mut self.configure_random_weak_links());
621 }
622
623 self.create_blocks(round, connections);
624 }
625
626 self.dag_builder.last_ancestors = self.ancestors.clone();
627 self
628 }
629
630 pub fn persist_layers(&self, dag_state: Arc<RwLock<DagState>>) {
631 assert!(
632 !self.blocks.is_empty(),
633 "Called to persist layers although no blocks have been created. Make sure you have called build before."
634 );
635 dag_state.write().accept_blocks(self.blocks.clone());
636 }
637
638 pub fn configure_min_parent_links(
640 &mut self,
641 round: Round,
642 ) -> Vec<(AuthorityIndex, Vec<BlockRef>)> {
643 let quorum_threshold = self.dag_builder.context.committee.quorum_threshold() as usize;
644 let authorities: Vec<AuthorityIndex> = self
645 .dag_builder
646 .context
647 .committee
648 .authorities()
649 .map(|authority| authority.0)
650 .collect();
651
652 let mut rng = match self.min_ancestor_links_random_seed {
653 Some(s) => StdRng::seed_from_u64(s),
654 None => StdRng::from_entropy(),
655 };
656
657 let mut authorities_to_shuffle = authorities.clone();
658
659 let mut leaders = vec![];
660 if let Some(leader_round) = self.leader_round {
661 let leader_offsets = (0..self.dag_builder.number_of_leaders).collect::<Vec<_>>();
662
663 for leader_offset in leader_offsets {
664 leaders.push(
665 self.dag_builder
666 .leader_schedule
667 .elect_leader(leader_round, leader_offset),
668 );
669 }
670 }
671
672 authorities
673 .iter()
674 .map(|authority| {
675 authorities_to_shuffle.shuffle(&mut rng);
676
677 let min_ancestors: HashSet<AuthorityIndex> = authorities_to_shuffle
679 .iter()
680 .take(quorum_threshold)
681 .cloned()
682 .collect();
683
684 (
685 *authority,
686 self.ancestors
687 .iter()
688 .filter(|a| {
689 leaders.contains(&a.author)
690 || min_ancestors.contains(&a.author)
691 || a.round != round
692 })
693 .cloned()
694 .collect::<Vec<BlockRef>>(),
695 )
696 })
697 .collect()
698 }
699
700 fn configure_random_weak_links(&mut self) -> Vec<(AuthorityIndex, Vec<BlockRef>)> {
702 unimplemented!("configure_random_weak_links");
703 }
704
705 fn configure_no_leader_links(
707 &mut self,
708 authorities: Vec<AuthorityIndex>,
709 _round: Round,
710 ) -> Vec<(AuthorityIndex, Vec<BlockRef>)> {
711 let mut missing_leaders = Vec::new();
712 let mut specified_leader_offsets = self
713 .specified_leader_link_offsets
714 .clone()
715 .expect("specified_leader_offsets should be set");
716 let leader_round = self.leader_round.expect("leader round should be set");
717
718 if specified_leader_offsets.is_empty() {
721 specified_leader_offsets.extend(0..self.dag_builder.number_of_leaders);
722 }
723
724 for leader_offset in specified_leader_offsets {
725 missing_leaders.push(
726 self.dag_builder
727 .leader_schedule
728 .elect_leader(leader_round, leader_offset),
729 );
730 }
731
732 self.configure_skipped_ancestor_links(authorities, missing_leaders)
733 }
734
735 fn configure_specifed_ancestors(&mut self) -> Vec<(AuthorityIndex, Vec<BlockRef>)> {
736 self.dag_builder
737 .context
738 .committee
739 .authorities()
740 .map(|authority| (authority.0, self.specified_ancestors.clone()))
741 .collect::<Vec<_>>()
742 }
743
744 fn configure_fully_linked_ancestors(
745 &mut self,
746 round: Round,
747 ) -> Vec<(AuthorityIndex, Vec<BlockRef>)> {
748 self.dag_builder
749 .context
750 .committee
751 .authorities()
752 .map(|authority| {
753 (
754 authority.0,
755 self.ancestors
757 .clone()
758 .into_iter()
759 .filter(|a| a.round != round)
760 .collect::<Vec<_>>(),
761 )
762 })
763 .collect::<Vec<_>>()
764 }
765
766 fn configure_skipped_ancestor_links(
767 &mut self,
768 authorities: Vec<AuthorityIndex>,
769 ancestors_to_skip: Vec<AuthorityIndex>,
770 ) -> Vec<(AuthorityIndex, Vec<BlockRef>)> {
771 let filtered_ancestors = self
772 .ancestors
773 .clone()
774 .into_iter()
775 .filter(|ancestor| !ancestors_to_skip.contains(&ancestor.author))
776 .collect::<Vec<_>>();
777 authorities
778 .into_iter()
779 .map(|authority| (authority, filtered_ancestors.clone()))
780 .collect::<Vec<_>>()
781 }
782
783 fn create_blocks(&mut self, round: Round, connections: Vec<(AuthorityIndex, Vec<BlockRef>)>) {
786 let mut references = Vec::new();
787 let mut reject_rng =
788 StdRng::seed_from_u64(self.rejected_transactions_seed ^ (round as u64));
789 for (authority, ancestors) in connections {
790 if self.should_skip_block(round, authority) {
791 continue;
792 };
793 let transactions = (0..self.num_transactions)
794 .map(|_| Transaction::new(vec![1_u8; 16]))
795 .collect::<Vec<_>>();
796 let num_blocks = self.num_blocks_to_create(authority);
797 for num_block in 0..num_blocks {
798 let mut votes = vec![];
799 if self.rejected_transactions_pct > 0 {
800 for ancestor in &ancestors {
801 let mut rejects = vec![];
802 for i in 0..self.num_transactions {
803 if reject_rng.gen_range(1..=100) <= self.rejected_transactions_pct {
804 rejects.push(i as TransactionIndex);
805 }
806 }
807 if !rejects.is_empty() {
808 votes.push(BlockTransactionVotes {
809 block_ref: *ancestor,
810 rejects,
811 });
812 }
813 }
814 }
815 let timestamp = self.block_timestamp(authority, round, num_block);
816 let block = VerifiedBlock::new_for_test(
817 TestBlock::new(round, authority.value() as u32)
818 .set_transactions(transactions.clone())
819 .set_transaction_votes(votes)
820 .set_ancestors(ancestors.clone())
821 .set_timestamp_ms(timestamp)
822 .build(),
823 );
824 references.push(block.reference());
825 self.dag_builder
826 .blocks
827 .insert(block.reference(), block.clone());
828 self.blocks.push(block);
829 }
830 }
831 self.ancestors = references;
832 }
833
834 fn num_blocks_to_create(&self, authority: AuthorityIndex) -> u32 {
835 if self.specified_authorities.is_some()
836 && self
837 .specified_authorities
838 .clone()
839 .unwrap()
840 .contains(&authority)
841 {
842 1 + self.equivocations as u32
844 } else {
845 1
846 }
847 }
848
849 fn block_timestamp(
850 &self,
851 authority: AuthorityIndex,
852 round: Round,
853 num_block: u32,
854 ) -> BlockTimestampMs {
855 if let Some(specified_authorities) = self.specified_authorities.as_ref()
856 && !self.timestamps.is_empty()
857 && let Some(position) = specified_authorities.iter().position(|&x| x == authority)
858 {
859 return self.timestamps[position] + (round + num_block) as u64;
860 }
861 let author = authority.value() as u32;
862 let base_ts = round as BlockTimestampMs * 1000;
863 base_ts + (author + round + num_block) as u64
864 }
865
866 fn should_skip_block(&self, round: Round, authority: AuthorityIndex) -> bool {
867 if self.skip_block
870 && self
871 .specified_authorities
872 .clone()
873 .unwrap()
874 .contains(&authority)
875 {
876 return true;
877 }
878 if self.no_leader_block {
879 let mut specified_leader_offsets = self
880 .specified_leader_block_offsets
881 .clone()
882 .expect("specified_leader_block_offsets should be set");
883
884 if specified_leader_offsets.is_empty() {
887 specified_leader_offsets.extend(0..self.dag_builder.number_of_leaders);
888 }
889
890 for leader_offset in specified_leader_offsets {
891 let leader = self
892 .dag_builder
893 .leader_schedule
894 .elect_leader(round, leader_offset);
895
896 if leader == authority {
897 return true;
898 }
899 }
900 }
901 false
902 }
903}