1use std::{collections::BTreeMap, pin::Pin, sync::Arc, time::Duration};
5
6use async_trait::async_trait;
7use bytes::Bytes;
8use consensus_config::AuthorityIndex;
9use consensus_types::block::{BlockRef, Round};
10use futures::{Stream, StreamExt, ready, stream, task};
11use mysten_metrics::spawn_monitored_task;
12use parking_lot::RwLock;
13use sui_macros::fail_point_async;
14use tap::TapFallible;
15use tokio::sync::broadcast;
16use tokio_util::sync::ReusableBoxFuture;
17use tracing::{debug, info, warn};
18
19use crate::{
20 block::{BlockAPI as _, ExtendedBlock, GENESIS_ROUND, SignedBlock, VerifiedBlock},
21 block_sync_service::BlockSyncService,
22 block_verifier::BlockVerifier,
23 commit::{CommitRange, TrustedCommit},
24 commit_vote_monitor::{CommitVoteMonitor, is_commit_lagging},
25 context::Context,
26 core_thread::CoreThreadDispatcher,
27 dag_state::DagState,
28 error::{ConsensusError, ConsensusResult},
29 network::{BlockStream, ExtendedSerializedBlock, PeerId, ValidatorNetworkService},
30 round_tracker::RoundTracker,
31 synchronizer::SynchronizerHandle,
32 transaction_vote_tracker::TransactionVoteTracker,
33};
34
35pub(crate) struct AuthorityService<C: CoreThreadDispatcher> {
37 context: Arc<Context>,
38 commit_vote_monitor: Arc<CommitVoteMonitor>,
39 block_verifier: Arc<dyn BlockVerifier>,
40 synchronizer: Arc<SynchronizerHandle>,
41 core_dispatcher: Arc<C>,
42 rx_block_broadcast: broadcast::Receiver<ExtendedBlock>,
43 subscription_counter: Arc<SubscriptionCounter>,
44 transaction_vote_tracker: TransactionVoteTracker,
45 dag_state: Arc<RwLock<DagState>>,
46 round_tracker: Arc<RwLock<RoundTracker>>,
47 block_sync_service: Arc<BlockSyncService>,
48}
49
50impl<C: CoreThreadDispatcher> AuthorityService<C> {
51 pub(crate) fn new(
52 context: Arc<Context>,
53 block_verifier: Arc<dyn BlockVerifier>,
54 commit_vote_monitor: Arc<CommitVoteMonitor>,
55 round_tracker: Arc<RwLock<RoundTracker>>,
56 synchronizer: Arc<SynchronizerHandle>,
57 core_dispatcher: Arc<C>,
58 rx_block_broadcast: broadcast::Receiver<ExtendedBlock>,
59 transaction_vote_tracker: TransactionVoteTracker,
60 dag_state: Arc<RwLock<DagState>>,
61 block_sync_service: Arc<BlockSyncService>,
62 ) -> Self {
63 let subscription_counter = Arc::new(SubscriptionCounter::new(context.clone()));
64 Self {
65 context,
66 block_verifier,
67 commit_vote_monitor,
68 synchronizer,
69 core_dispatcher,
70 rx_block_broadcast,
71 subscription_counter,
72 transaction_vote_tracker,
73 dag_state,
74 round_tracker,
75 block_sync_service,
76 }
77 }
78
79 fn parse_excluded_ancestors(
81 &self,
82 peer: AuthorityIndex,
83 block: &VerifiedBlock,
84 mut excluded_ancestors: Vec<Vec<u8>>,
85 ) -> ConsensusResult<Vec<BlockRef>> {
86 let peer_hostname = &self.context.committee.authority(peer).hostname;
87
88 let excluded_ancestors_limit = self.context.committee.size() * 2;
89 if excluded_ancestors.len() > excluded_ancestors_limit {
90 debug!(
91 "Dropping {} excluded ancestor(s) from {} {} due to size limit",
92 excluded_ancestors.len() - excluded_ancestors_limit,
93 peer,
94 peer_hostname,
95 );
96 excluded_ancestors.truncate(excluded_ancestors_limit);
97 }
98
99 let excluded_ancestors = excluded_ancestors
100 .into_iter()
101 .map(|serialized| {
102 let block_ref: BlockRef =
103 bcs::from_bytes(&serialized).map_err(ConsensusError::MalformedBlock)?;
104 if !self.context.committee.is_valid_index(block_ref.author) {
105 return Err(ConsensusError::InvalidAuthorityIndex {
106 index: block_ref.author,
107 max: self.context.committee.size(),
108 });
109 }
110 if block_ref.round >= block.round() {
111 return Err(ConsensusError::InvalidAncestorRound {
112 ancestor: block_ref.round,
113 block: block.round(),
114 });
115 }
116 Ok(block_ref)
117 })
118 .collect::<ConsensusResult<Vec<BlockRef>>>()?;
119
120 for excluded_ancestor in &excluded_ancestors {
121 let excluded_ancestor_hostname = &self
122 .context
123 .committee
124 .authority(excluded_ancestor.author)
125 .hostname;
126 self.context
127 .metrics
128 .node_metrics
129 .network_excluded_ancestors_count_by_authority
130 .with_label_values(&[excluded_ancestor_hostname])
131 .inc();
132 }
133 self.context
134 .metrics
135 .node_metrics
136 .network_received_excluded_ancestors_from_authority
137 .with_label_values(&[peer_hostname])
138 .inc_by(excluded_ancestors.len() as u64);
139
140 Ok(excluded_ancestors)
141 }
142}
143
144#[async_trait]
145impl<C: CoreThreadDispatcher> ValidatorNetworkService for AuthorityService<C> {
146 async fn handle_send_block(
147 &self,
148 peer: AuthorityIndex,
149 serialized_block: ExtendedSerializedBlock,
150 ) -> ConsensusResult<()> {
151 fail_point_async!("consensus-rpc-response");
152
153 let peer_hostname = &self.context.committee.authority(peer).hostname;
154
155 let signed_block: SignedBlock =
157 bcs::from_bytes(&serialized_block.block).map_err(ConsensusError::MalformedBlock)?;
158
159 if peer != signed_block.author() {
161 self.context
162 .metrics
163 .node_metrics
164 .invalid_blocks
165 .with_label_values(&[
166 peer_hostname.as_str(),
167 "handle_send_block",
168 "UnexpectedAuthority",
169 ])
170 .inc();
171 let e = ConsensusError::UnexpectedAuthority(signed_block.author(), peer);
172 info!("Block with wrong authority from {}: {}", peer, e);
173 return Err(e);
174 }
175
176 let (verified_block, reject_txn_votes) = self
178 .block_verifier
179 .verify_and_vote(signed_block, serialized_block.block)
180 .tap_err(|e| {
181 self.context
182 .metrics
183 .node_metrics
184 .invalid_blocks
185 .with_label_values(&[peer_hostname.as_str(), "handle_send_block", e.name()])
186 .inc();
187 info!("Invalid block from {}: {}", peer, e);
188 })?;
189 let excluded_ancestors = self
190 .parse_excluded_ancestors(peer, &verified_block, serialized_block.excluded_ancestors)
191 .tap_err(|e| {
192 debug!("Failed to parse excluded ancestors from {peer} {peer_hostname}: {e}");
193 self.context
194 .metrics
195 .node_metrics
196 .invalid_blocks
197 .with_label_values(&[peer_hostname.as_str(), "handle_send_block", e.name()])
198 .inc();
199 })?;
200
201 let block_ref = verified_block.reference();
202 debug!("Received block {} via send block.", block_ref);
203
204 self.context
205 .metrics
206 .node_metrics
207 .verified_blocks
208 .with_label_values(&[peer_hostname])
209 .inc();
210
211 let now = self.context.clock.timestamp_utc_ms();
212 let forward_time_drift =
213 Duration::from_millis(verified_block.timestamp_ms().saturating_sub(now));
214
215 self.context
216 .metrics
217 .node_metrics
218 .block_timestamp_drift_ms
219 .with_label_values(&[peer_hostname.as_str(), "handle_send_block"])
220 .inc_by(forward_time_drift.as_millis() as u64);
221
222 self.commit_vote_monitor.observe_block(&verified_block);
225
226 self.round_tracker
228 .write()
229 .update_from_verified_block(&ExtendedBlock {
230 block: verified_block.clone(),
231 excluded_ancestors: excluded_ancestors.clone(),
232 });
233
234 let last_commit_index = self.dag_state.read().last_commit_index();
243 let quorum_commit_index = self.commit_vote_monitor.quorum_commit_index();
244 if is_commit_lagging(
245 self.context.as_ref(),
246 last_commit_index,
247 quorum_commit_index,
248 ) {
249 self.context
250 .metrics
251 .node_metrics
252 .rejected_blocks
253 .with_label_values(&["commit_lagging"])
254 .inc();
255 debug!(
256 "Block {:?} is rejected because last commit index is lagging quorum commit index too much ({} < {})",
257 block_ref, last_commit_index, quorum_commit_index,
258 );
259 return Err(ConsensusError::BlockRejected {
260 block_ref,
261 reason: format!(
262 "Last commit index is lagging quorum commit index too much ({} < {})",
263 last_commit_index, quorum_commit_index,
264 ),
265 });
266 }
267
268 if self.context.protocol_config.transaction_voting_enabled() {
271 self.transaction_vote_tracker
272 .add_voted_blocks(vec![(verified_block.clone(), reject_txn_votes)]);
273 }
274
275 let missing_ancestors = self
277 .core_dispatcher
278 .add_blocks(vec![verified_block.clone()])
279 .await
280 .map_err(|_| ConsensusError::Shutdown)?;
281
282 if !missing_ancestors.is_empty() {
284 self.context
285 .metrics
286 .node_metrics
287 .handler_received_block_missing_ancestors
288 .with_label_values(&[peer_hostname])
289 .inc_by(missing_ancestors.len() as u64);
290 let synchronizer = self.synchronizer.clone();
291 spawn_monitored_task!(async move {
292 if let Err(err) = synchronizer
297 .fetch_blocks(missing_ancestors, PeerId::Validator(peer))
298 .await
299 {
300 debug!("Failed to fetch missing ancestors via synchronizer: {err}");
301 }
302 });
303 }
304
305 let missing_excluded_ancestors = self
307 .core_dispatcher
308 .check_block_refs(excluded_ancestors)
309 .await
310 .map_err(|_| ConsensusError::Shutdown)?;
311 if !missing_excluded_ancestors.is_empty() {
312 self.context
313 .metrics
314 .node_metrics
315 .network_excluded_ancestors_sent_to_fetch
316 .with_label_values(&[peer_hostname])
317 .inc_by(missing_excluded_ancestors.len() as u64);
318
319 let synchronizer = self.synchronizer.clone();
320 spawn_monitored_task!(async move {
321 if let Err(err) = synchronizer
322 .fetch_blocks(missing_excluded_ancestors, PeerId::Validator(peer))
323 .await
324 {
325 debug!("Failed to fetch excluded ancestors via synchronizer: {err}");
326 }
327 });
328 }
329
330 Ok(())
331 }
332
333 async fn handle_subscribe_blocks(
334 &self,
335 peer: AuthorityIndex,
336 last_received: Round,
337 ) -> ConsensusResult<BlockStream> {
338 fail_point_async!("consensus-rpc-response");
339
340 let broadcast_rx = self.rx_block_broadcast.resubscribe();
345
346 let past_proposed_blocks = {
355 let dag_state = self.dag_state.read();
356
357 let mut proposed_blocks = dag_state
360 .get_cached_blocks(self.context.own_index, last_received.saturating_add(1));
361 if proposed_blocks.is_empty() {
362 let last_proposed_block = dag_state
363 .get_last_proposed_block()
364 .expect("Last proposed block should be returned on validators");
365 proposed_blocks = if last_proposed_block.round() > GENESIS_ROUND {
366 vec![last_proposed_block]
367 } else {
368 vec![]
369 };
370 }
371 stream::iter(
372 proposed_blocks
373 .into_iter()
374 .map(|block| ExtendedSerializedBlock {
375 block: block.serialized().clone(),
376 excluded_ancestors: vec![],
377 }),
378 )
379 };
380
381 const MAX_BLOCKS_PER_POLL: usize = 1;
383 let broadcasted_blocks = BroadcastedBlockStream::new(
384 PeerId::Validator(peer),
385 broadcast_rx,
386 MAX_BLOCKS_PER_POLL,
387 self.subscription_counter.clone(),
388 );
389
390 Ok(Box::pin(past_proposed_blocks.chain(
392 broadcasted_blocks.flat_map(|items| {
393 debug_assert!(
394 items.len() <= MAX_BLOCKS_PER_POLL,
395 "Too many blocks received from broadcast"
396 );
397 stream::iter(items.into_iter().map(ExtendedSerializedBlock::from))
398 }),
399 )))
400 }
401
402 async fn handle_fetch_blocks(
418 &self,
419 _peer: AuthorityIndex,
420 block_refs: Vec<BlockRef>,
421 fetch_after_rounds: Vec<Round>,
422 fetch_missing_ancestors: bool,
423 ) -> ConsensusResult<Vec<Bytes>> {
424 fail_point_async!("consensus-rpc-response");
425
426 self.block_sync_service
428 .fetch_blocks(block_refs, fetch_after_rounds, fetch_missing_ancestors)
429 .await
430 }
431
432 async fn handle_fetch_commits(
433 &self,
434 _peer: AuthorityIndex,
435 commit_range: CommitRange,
436 ) -> ConsensusResult<(Vec<TrustedCommit>, Vec<VerifiedBlock>)> {
437 fail_point_async!("consensus-rpc-response");
438
439 self.block_sync_service.fetch_commits(commit_range).await
441 }
442
443 async fn handle_fetch_latest_blocks(
444 &self,
445 peer: AuthorityIndex,
446 authorities: Vec<AuthorityIndex>,
447 ) -> ConsensusResult<Vec<Bytes>> {
448 fail_point_async!("consensus-rpc-response");
449
450 self.block_sync_service
452 .fetch_latest_blocks(peer, authorities)
453 .await
454 }
455
456 async fn handle_get_latest_rounds(
457 &self,
458 _peer: AuthorityIndex,
459 ) -> ConsensusResult<(Vec<Round>, Vec<Round>)> {
460 fail_point_async!("consensus-rpc-response");
461
462 let highest_received_rounds = self.round_tracker.read().local_highest_received_rounds();
463
464 let blocks = self
465 .dag_state
466 .read()
467 .get_last_cached_block_per_authority(Round::MAX);
468 let highest_accepted_rounds = blocks
469 .into_iter()
470 .map(|(block, _)| block.round())
471 .collect::<Vec<_>>();
472
473 Ok((highest_received_rounds, highest_accepted_rounds))
474 }
475}
476
477struct Counter {
478 count: usize,
479 subscriptions_by_peer: BTreeMap<PeerId, usize>,
480}
481
482pub(crate) struct SubscriptionCounter {
484 context: Arc<Context>,
485 counter: parking_lot::Mutex<Counter>,
486}
487
488impl SubscriptionCounter {
489 pub(crate) fn new(context: Arc<Context>) -> Self {
490 for (_, authority) in context.committee.authorities() {
492 context
493 .metrics
494 .node_metrics
495 .subscribed_by
496 .with_label_values(&[authority.hostname.as_str()])
497 .set(0);
498 }
499
500 Self {
501 counter: parking_lot::Mutex::new(Counter {
502 count: 0,
503 subscriptions_by_peer: BTreeMap::new(),
504 }),
505 context,
506 }
507 }
508
509 fn increment(&self, peer: &PeerId) {
510 let mut counter = self.counter.lock();
511 counter.count += 1;
512 let peer_count = {
513 let count = counter
514 .subscriptions_by_peer
515 .entry(peer.clone())
516 .or_default();
517 *count += 1;
518 *count
519 };
520
521 match peer {
522 PeerId::Validator(authority) => {
523 let peer_hostname = &self.context.committee.authority(*authority).hostname;
524 self.context
525 .metrics
526 .node_metrics
527 .subscribed_by
528 .with_label_values(&[peer_hostname])
529 .set(1);
530 }
531 PeerId::Observer(_) => {
532 if peer_count == 1 {
534 self.context
535 .metrics
536 .node_metrics
537 .subscribed_by
538 .with_label_values(&["observer"])
539 .inc();
540 }
541 }
542 }
543 }
544
545 fn decrement(&self, peer: &PeerId) {
546 let mut counter = self.counter.lock();
547 counter.count = counter.count.saturating_sub(1);
548 let peer_count = counter
549 .subscriptions_by_peer
550 .entry(peer.clone())
551 .or_default();
552 *peer_count = peer_count.saturating_sub(1);
553
554 if *peer_count == 0 {
555 match peer {
556 PeerId::Validator(authority) => {
557 let peer_hostname = &self.context.committee.authority(*authority).hostname;
558 self.context
559 .metrics
560 .node_metrics
561 .subscribed_by
562 .with_label_values(&[peer_hostname])
563 .set(0);
564 }
565 PeerId::Observer(_) => {
566 self.context
567 .metrics
568 .node_metrics
569 .subscribed_by
570 .with_label_values(&["observer"])
571 .dec();
572 }
573 }
574 }
575 }
576}
577
578type BroadcastedBlockStream = BroadcastStream<ExtendedBlock>;
581
582pub(crate) struct BroadcastStream<T> {
585 peer: Option<PeerId>,
586 inner: ReusableBoxFuture<
588 'static,
589 (
590 Result<T, broadcast::error::RecvError>,
591 broadcast::Receiver<T>,
592 ),
593 >,
594 max_items_per_poll: usize,
596 subscription_counter: Option<Arc<SubscriptionCounter>>,
598}
599
600impl<T: 'static + Clone + Send> BroadcastStream<T> {
601 pub fn new(
602 peer: PeerId,
603 rx: broadcast::Receiver<T>,
604 max_items_per_poll: usize,
605 subscription_counter: Arc<SubscriptionCounter>,
606 ) -> Self {
607 assert!(max_items_per_poll > 0, "max_items_per_poll must be > 0");
608 subscription_counter.increment(&peer);
609 Self {
610 peer: Some(peer),
611 inner: ReusableBoxFuture::new(make_recv_future(rx)),
612 max_items_per_poll,
613 subscription_counter: Some(subscription_counter),
614 }
615 }
616
617 pub fn new_untracked(rx: broadcast::Receiver<T>, max_items_per_poll: usize) -> Self {
619 assert!(max_items_per_poll > 0, "max_items_per_poll must be > 0");
620 Self {
621 peer: None,
622 inner: ReusableBoxFuture::new(make_recv_future(rx)),
623 max_items_per_poll,
624 subscription_counter: None,
625 }
626 }
627}
628
629impl<T: 'static + Clone + Send> Stream for BroadcastStream<T> {
630 type Item = Vec<T>;
631
632 fn poll_next(
633 mut self: Pin<&mut Self>,
634 cx: &mut task::Context<'_>,
635 ) -> task::Poll<Option<Self::Item>> {
636 loop {
637 let (result, mut rx) = ready!(self.inner.poll(cx));
638
639 match result {
640 Ok(item) => {
641 let mut items = Vec::new();
642 items.push(item);
643
644 while items.len() < self.max_items_per_poll {
646 match rx.try_recv() {
647 Ok(item) => items.push(item),
648 Err(broadcast::error::TryRecvError::Empty) => break,
649 Err(broadcast::error::TryRecvError::Closed) => break,
650 Err(broadcast::error::TryRecvError::Lagged(n)) => {
651 warn!("BroadcastStream {:?} lagged by {} messages", self.peer, n);
652 break;
653 }
654 }
655 }
656
657 self.inner.set(make_recv_future(rx));
658 return task::Poll::Ready(Some(items));
659 }
660 Err(broadcast::error::RecvError::Closed) => {
661 info!("BroadcastStream {:?} closed", self.peer);
662 return task::Poll::Ready(None);
663 }
664 Err(broadcast::error::RecvError::Lagged(n)) => {
665 warn!("BroadcastStream {:?} lagged by {} messages", self.peer, n);
666 self.inner.set(make_recv_future(rx));
668 continue;
669 }
670 }
671 }
672 }
673}
674
675impl<T> Drop for BroadcastStream<T> {
676 fn drop(&mut self) {
677 if let (Some(counter), Some(peer)) = (&self.subscription_counter, &self.peer) {
678 counter.decrement(peer);
679 }
680 }
681}
682
683async fn make_recv_future<T: Clone>(
684 mut rx: broadcast::Receiver<T>,
685) -> (
686 Result<T, broadcast::error::RecvError>,
687 broadcast::Receiver<T>,
688) {
689 let result = rx.recv().await;
690 (result, rx)
691}
692
693#[cfg(test)]
694mod tests {
695 use std::{
696 collections::{BTreeMap, BTreeSet},
697 sync::Arc,
698 time::Duration,
699 };
700
701 use async_trait::async_trait;
702 use bytes::Bytes;
703 use consensus_config::AuthorityIndex;
704 use consensus_types::block::{BlockDigest, BlockRef, Round};
705 use parking_lot::{Mutex, RwLock};
706 use tokio::{sync::broadcast, time::sleep};
707
708 use futures::StreamExt as _;
709
710 use crate::{
711 authority_service::AuthorityService,
712 block::{BlockAPI, SignedBlock, TestBlock, VerifiedBlock},
713 block_sync_service::BlockSyncService,
714 commit::{CertifiedCommits, CommitRange},
715 commit_vote_monitor::CommitVoteMonitor,
716 context::Context,
717 core_thread::{CoreError, CoreThreadDispatcher},
718 dag_state::DagState,
719 error::ConsensusResult,
720 network::{
721 BlockStream, ExtendedSerializedBlock, ObserverNetworkClient, SynchronizerClient,
722 ValidatorNetworkClient, ValidatorNetworkService,
723 },
724 peers_pool::PeersPool,
725 round_tracker::RoundTracker,
726 storage::mem_store::MemStore,
727 synchronizer::Synchronizer,
728 test_dag_builder::DagBuilder,
729 transaction_vote_tracker::TransactionVoteTracker,
730 };
731 struct FakeCoreThreadDispatcher {
732 blocks: Mutex<Vec<VerifiedBlock>>,
733 }
734
735 impl FakeCoreThreadDispatcher {
736 fn new() -> Self {
737 Self {
738 blocks: Mutex::new(vec![]),
739 }
740 }
741
742 fn get_blocks(&self) -> Vec<VerifiedBlock> {
743 self.blocks.lock().clone()
744 }
745 }
746
747 #[async_trait]
748 impl CoreThreadDispatcher for FakeCoreThreadDispatcher {
749 async fn add_blocks(
750 &self,
751 blocks: Vec<VerifiedBlock>,
752 ) -> Result<BTreeSet<BlockRef>, CoreError> {
753 let block_refs = blocks.iter().map(|b| b.reference()).collect();
754 self.blocks.lock().extend(blocks);
755 Ok(block_refs)
756 }
757
758 async fn check_block_refs(
759 &self,
760 _block_refs: Vec<BlockRef>,
761 ) -> Result<BTreeSet<BlockRef>, CoreError> {
762 Ok(BTreeSet::new())
763 }
764
765 async fn add_certified_commits(
766 &self,
767 _commits: CertifiedCommits,
768 ) -> Result<BTreeSet<BlockRef>, CoreError> {
769 todo!()
770 }
771
772 async fn new_block(&self, _round: Round, _force: bool) -> Result<(), CoreError> {
773 Ok(())
774 }
775
776 async fn get_missing_blocks(&self) -> Result<BTreeSet<BlockRef>, CoreError> {
777 Ok(Default::default())
778 }
779
780 fn set_propagation_delay(&self, _propagation_delay: Round) -> Result<(), CoreError> {
781 todo!()
782 }
783
784 fn set_last_known_proposed_round(&self, _round: Round) -> Result<(), CoreError> {
785 todo!()
786 }
787 }
788
789 #[derive(Default)]
790 struct FakeNetworkClient {}
791
792 #[async_trait]
793 impl ValidatorNetworkClient for FakeNetworkClient {
794 async fn send_block(
795 &self,
796 _peer: AuthorityIndex,
797 _block: &VerifiedBlock,
798 _timeout: Duration,
799 ) -> ConsensusResult<()> {
800 unimplemented!("Unimplemented")
801 }
802
803 async fn subscribe_blocks(
804 &self,
805 _peer: AuthorityIndex,
806 _last_received: Round,
807 _timeout: Duration,
808 ) -> ConsensusResult<BlockStream> {
809 unimplemented!("Unimplemented")
810 }
811
812 async fn fetch_blocks(
813 &self,
814 _peer: AuthorityIndex,
815 _block_refs: Vec<BlockRef>,
816 _fetch_after_rounds: Vec<Round>,
817 _fetch_missing_ancestors: bool,
818 _timeout: Duration,
819 ) -> ConsensusResult<Vec<Bytes>> {
820 unimplemented!("Unimplemented")
821 }
822
823 async fn fetch_commits(
824 &self,
825 _peer: AuthorityIndex,
826 _commit_range: CommitRange,
827 _timeout: Duration,
828 ) -> ConsensusResult<(Vec<Bytes>, Vec<Bytes>)> {
829 unimplemented!("Unimplemented")
830 }
831
832 async fn fetch_latest_blocks(
833 &self,
834 _peer: AuthorityIndex,
835 _authorities: Vec<AuthorityIndex>,
836 _timeout: Duration,
837 ) -> ConsensusResult<Vec<Bytes>> {
838 unimplemented!("Unimplemented")
839 }
840
841 async fn get_latest_rounds(
842 &self,
843 _peer: AuthorityIndex,
844 _timeout: Duration,
845 ) -> ConsensusResult<(Vec<Round>, Vec<Round>)> {
846 unimplemented!("Unimplemented")
847 }
848 }
849
850 #[async_trait]
851 impl ObserverNetworkClient for FakeNetworkClient {
852 async fn stream_blocks(
853 &self,
854 _peer: crate::network::PeerId,
855 _highest_round_per_authority: Vec<Round>,
856 _timeout: Duration,
857 ) -> ConsensusResult<crate::network::ObserverBlockStream> {
858 unimplemented!("Unimplemented")
859 }
860
861 async fn fetch_blocks(
862 &self,
863 _peer: crate::network::PeerId,
864 _block_refs: Vec<BlockRef>,
865 _fetch_after_rounds: Vec<Round>,
866 _fetch_missing_ancestors: bool,
867 _timeout: Duration,
868 ) -> ConsensusResult<Vec<Bytes>> {
869 unimplemented!("Unimplemented")
870 }
871
872 async fn fetch_commits(
873 &self,
874 _peer: crate::network::PeerId,
875 _commit_range: CommitRange,
876 _timeout: Duration,
877 ) -> ConsensusResult<(Vec<Bytes>, Vec<Bytes>)> {
878 unimplemented!("Unimplemented")
879 }
880 }
881
882 #[tokio::test(flavor = "current_thread", start_paused = true)]
883 async fn test_handle_send_block() {
884 let (context, _keys) = Context::new_for_test(4);
885 let context = Arc::new(context);
886 let block_verifier = Arc::new(crate::block_verifier::NoopBlockVerifier {});
887 let commit_vote_monitor = Arc::new(CommitVoteMonitor::new(context.clone()));
888 let core_dispatcher = Arc::new(FakeCoreThreadDispatcher::new());
889 let (_tx_block_broadcast, rx_block_broadcast) = broadcast::channel(100);
890 let fake_client = Arc::new(FakeNetworkClient::default());
891 let network_client = Arc::new(SynchronizerClient::new(
892 context.clone(),
893 Some(fake_client.clone()),
894 Some(fake_client.clone()),
895 ));
896 let store = Arc::new(MemStore::new());
897 let dag_state = Arc::new(RwLock::new(DagState::new(context.clone(), store.clone())));
898 let transaction_vote_tracker =
899 TransactionVoteTracker::new(context.clone(), block_verifier.clone(), dag_state.clone());
900 let round_tracker = Arc::new(RwLock::new(RoundTracker::new(context.clone(), vec![])));
901 let peers_pool = Arc::new(PeersPool::new(context.clone()));
902 let synchronizer = Synchronizer::start(
903 network_client,
904 context.clone(),
905 core_dispatcher.clone(),
906 commit_vote_monitor.clone(),
907 block_verifier.clone(),
908 transaction_vote_tracker.clone(),
909 round_tracker.clone(),
910 dag_state.clone(),
911 peers_pool.clone(),
912 false,
913 );
914 let block_sync_service = Arc::new(BlockSyncService::new(
915 context.clone(),
916 dag_state.clone(),
917 store.clone(),
918 ));
919 let authority_service = Arc::new(AuthorityService::new(
920 context.clone(),
921 block_verifier,
922 commit_vote_monitor,
923 round_tracker,
924 synchronizer,
925 core_dispatcher.clone(),
926 rx_block_broadcast,
927 transaction_vote_tracker,
928 dag_state,
929 block_sync_service,
930 ));
931
932 let now = context.clock.timestamp_utc_ms();
934 let max_drift = context.parameters.max_forward_time_drift;
935 let input_block = VerifiedBlock::new_for_test(
936 TestBlock::new(9, 0)
937 .set_timestamp_ms(now + max_drift.as_millis() as u64)
938 .build(),
939 );
940
941 let service = authority_service.clone();
942 let serialized = ExtendedSerializedBlock {
943 block: input_block.serialized().clone(),
944 excluded_ancestors: vec![],
945 };
946
947 tokio::spawn({
948 let service = service.clone();
949 let context = context.clone();
950 async move {
951 service
952 .handle_send_block(context.committee.to_authority_index(0).unwrap(), serialized)
953 .await
954 .unwrap();
955 }
956 });
957
958 sleep(max_drift / 2).await;
959
960 let blocks = core_dispatcher.get_blocks();
961 assert_eq!(blocks.len(), 1);
962 assert_eq!(blocks[0], input_block);
963
964 let invalid_block =
966 VerifiedBlock::new_for_test(TestBlock::new(10, 1000).set_timestamp_ms(10).build());
967 let extended_block = ExtendedSerializedBlock {
968 block: invalid_block.serialized().clone(),
969 excluded_ancestors: vec![],
970 };
971 service
972 .handle_send_block(
973 context.committee.to_authority_index(0).unwrap(),
974 extended_block,
975 )
976 .await
977 .unwrap_err();
978
979 let invalid_excluded_ancestors = vec![
981 bcs::to_bytes(&BlockRef::new(
982 10,
983 AuthorityIndex::new_for_test(1000),
984 BlockDigest::MIN,
985 ))
986 .unwrap(),
987 vec![3u8; 40],
988 bcs::to_bytes(&invalid_block.reference()).unwrap(),
989 ];
990 let extended_block = ExtendedSerializedBlock {
991 block: input_block.serialized().clone(),
992 excluded_ancestors: invalid_excluded_ancestors,
993 };
994 service
995 .handle_send_block(
996 context.committee.to_authority_index(0).unwrap(),
997 extended_block,
998 )
999 .await
1000 .unwrap_err();
1001 }
1002
1003 #[tokio::test(flavor = "current_thread", start_paused = true)]
1004 async fn test_handle_fetch_blocks() {
1005 const NUM_AUTHORITIES: usize = 40;
1008 const NUM_ROUNDS: usize = 40;
1009 let (mut context, _keys) = Context::new_for_test(NUM_AUTHORITIES);
1010 context.parameters.max_blocks_per_fetch = 50;
1011 let context = Arc::new(context);
1012 let block_verifier = Arc::new(crate::block_verifier::NoopBlockVerifier {});
1013 let commit_vote_monitor = Arc::new(CommitVoteMonitor::new(context.clone()));
1014 let core_dispatcher = Arc::new(FakeCoreThreadDispatcher::new());
1015 let (_tx_block_broadcast, rx_block_broadcast) = broadcast::channel(100);
1016 let fake_client = Arc::new(FakeNetworkClient::default());
1017 let network_client = Arc::new(SynchronizerClient::new(
1018 context.clone(),
1019 Some(fake_client.clone()),
1020 Some(fake_client.clone()),
1021 ));
1022 let store = Arc::new(MemStore::new());
1023 let dag_state = Arc::new(RwLock::new(DagState::new(context.clone(), store.clone())));
1024 let transaction_vote_tracker =
1025 TransactionVoteTracker::new(context.clone(), block_verifier.clone(), dag_state.clone());
1026 let round_tracker = Arc::new(RwLock::new(RoundTracker::new(context.clone(), vec![])));
1027 let peers_pool = Arc::new(PeersPool::new(context.clone()));
1028 let synchronizer = Synchronizer::start(
1029 network_client,
1030 context.clone(),
1031 core_dispatcher.clone(),
1032 commit_vote_monitor.clone(),
1033 block_verifier.clone(),
1034 transaction_vote_tracker.clone(),
1035 round_tracker.clone(),
1036 dag_state.clone(),
1037 peers_pool.clone(),
1038 false,
1039 );
1040 let block_sync_service = Arc::new(BlockSyncService::new(
1041 context.clone(),
1042 dag_state.clone(),
1043 store.clone(),
1044 ));
1045 let authority_service = Arc::new(AuthorityService::new(
1046 context.clone(),
1047 block_verifier,
1048 commit_vote_monitor,
1049 round_tracker,
1050 synchronizer,
1051 core_dispatcher.clone(),
1052 rx_block_broadcast,
1053 transaction_vote_tracker,
1054 dag_state.clone(),
1055 block_sync_service,
1056 ));
1057
1058 let mut dag_builder = DagBuilder::new(context.clone());
1060 dag_builder
1061 .layers(1..=(NUM_ROUNDS as u32))
1062 .build()
1063 .persist_layers(dag_state.clone());
1064 dag_state.write().flush();
1065 let all_blocks = dag_builder.all_blocks();
1066
1067 let missing_block_refs: Vec<BlockRef> = all_blocks
1069 .iter()
1070 .rev()
1071 .take(2)
1072 .map(|b| b.reference())
1073 .collect();
1074 let highest_accepted_rounds: Vec<Round> = vec![1; NUM_AUTHORITIES];
1075 let results = authority_service
1076 .handle_fetch_blocks(
1077 AuthorityIndex::new_for_test(0),
1078 missing_block_refs.clone(),
1079 highest_accepted_rounds,
1080 true,
1081 )
1082 .await
1083 .unwrap();
1084
1085 let blocks: BTreeMap<BlockRef, VerifiedBlock> = results
1087 .iter()
1088 .map(|b| {
1089 let signed = bcs::from_bytes(b).unwrap();
1090 let block = VerifiedBlock::new_verified(signed, b.clone());
1091 (block.reference(), block)
1092 })
1093 .collect();
1094 assert_eq!(blocks.len(), context.parameters.max_blocks_per_sync);
1095 for b in &missing_block_refs {
1097 assert!(blocks.contains_key(b));
1098 }
1099 let num_missing_ancestors = blocks
1100 .keys()
1101 .filter(|b| b.round == NUM_ROUNDS as Round - 1)
1102 .count();
1103 assert_eq!(
1104 num_missing_ancestors,
1105 context.parameters.max_blocks_per_sync - missing_block_refs.len()
1106 );
1107
1108 let missing_round = NUM_ROUNDS as Round - 3;
1110 let missing_block_refs: Vec<BlockRef> = all_blocks
1111 .iter()
1112 .filter(|b| b.reference().round == missing_round)
1113 .map(|b| b.reference())
1114 .take(2)
1115 .collect();
1116 let mut highest_accepted_rounds: Vec<Round> = vec![1; NUM_AUTHORITIES];
1117 highest_accepted_rounds[missing_block_refs[0].author] = missing_round - 5;
1119 let results = authority_service
1120 .handle_fetch_blocks(
1121 AuthorityIndex::new_for_test(0),
1122 missing_block_refs.clone(),
1123 highest_accepted_rounds,
1124 false,
1125 )
1126 .await
1127 .unwrap();
1128
1129 let blocks: BTreeMap<BlockRef, VerifiedBlock> = results
1131 .iter()
1132 .map(|b| {
1133 let signed = bcs::from_bytes(b).unwrap();
1134 let block = VerifiedBlock::new_verified(signed, b.clone());
1135 (block.reference(), block)
1136 })
1137 .collect();
1138 assert_eq!(blocks.len(), context.parameters.max_blocks_per_sync);
1139 for b in &missing_block_refs {
1141 assert!(blocks.contains_key(b));
1142 }
1143 let expected_authors = [missing_block_refs[0].author, missing_block_refs[1].author];
1145 for b in blocks.keys() {
1146 assert!(b.round <= missing_round);
1147 assert!(expected_authors.contains(&b.author));
1148 }
1149
1150 let mut highest_accepted_rounds: Vec<Round> = vec![1; NUM_AUTHORITIES];
1152 highest_accepted_rounds[0] = (NUM_ROUNDS as Round) - 5;
1154 highest_accepted_rounds[1] = (NUM_ROUNDS as Round) - 3;
1155 let results = authority_service
1156 .handle_fetch_blocks(
1157 AuthorityIndex::new_for_test(0),
1158 vec![],
1159 highest_accepted_rounds.clone(),
1160 false,
1161 )
1162 .await
1163 .unwrap();
1164
1165 let blocks: BTreeMap<BlockRef, VerifiedBlock> = results
1167 .iter()
1168 .map(|b| {
1169 let signed = bcs::from_bytes(b).unwrap();
1170 let block = VerifiedBlock::new_verified(signed, b.clone());
1171 (block.reference(), block)
1172 })
1173 .collect();
1174 assert_eq!(blocks.len(), context.parameters.max_blocks_per_fetch);
1175 for block_ref in blocks.keys() {
1177 let accepted = highest_accepted_rounds[block_ref.author];
1178 assert!(block_ref.round > accepted);
1179 }
1180 let max_round_in_result = blocks.keys().map(|b| b.round).max().unwrap();
1183 assert!(
1186 max_round_in_result <= 4,
1187 "Expected low rounds from fair round-order fetching, got max round {}",
1188 max_round_in_result
1189 );
1190
1191 let missing_block_refs: Vec<BlockRef> = all_blocks
1193 .iter()
1194 .filter(|b| b.reference().round == NUM_ROUNDS as Round - 10)
1195 .map(|b| b.reference())
1196 .take(5)
1197 .collect();
1198 let results = authority_service
1199 .handle_fetch_blocks(
1200 AuthorityIndex::new_for_test(0),
1201 missing_block_refs.clone(),
1202 vec![],
1203 false,
1204 )
1205 .await
1206 .unwrap();
1207
1208 let blocks: BTreeMap<BlockRef, VerifiedBlock> = results
1210 .iter()
1211 .map(|b| {
1212 let signed = bcs::from_bytes(b).unwrap();
1213 let block = VerifiedBlock::new_verified(signed, b.clone());
1214 (block.reference(), block)
1215 })
1216 .collect();
1217 assert_eq!(blocks.len(), 5);
1218 for b in &missing_block_refs {
1219 assert!(blocks.contains_key(b));
1220 }
1221 }
1222
1223 #[tokio::test(flavor = "current_thread", start_paused = true)]
1224 async fn test_handle_fetch_latest_blocks() {
1225 let (context, _keys) = Context::new_for_test(4);
1227 let context = Arc::new(context);
1228 let block_verifier = Arc::new(crate::block_verifier::NoopBlockVerifier {});
1229 let commit_vote_monitor = Arc::new(CommitVoteMonitor::new(context.clone()));
1230 let core_dispatcher = Arc::new(FakeCoreThreadDispatcher::new());
1231 let (_tx_block_broadcast, rx_block_broadcast) = broadcast::channel(100);
1232 let fake_client = Arc::new(FakeNetworkClient::default());
1233 let network_client = Arc::new(SynchronizerClient::new(
1234 context.clone(),
1235 Some(fake_client.clone()),
1236 Some(fake_client.clone()),
1237 ));
1238 let store = Arc::new(MemStore::new());
1239 let dag_state = Arc::new(RwLock::new(DagState::new(context.clone(), store.clone())));
1240 let transaction_vote_tracker =
1241 TransactionVoteTracker::new(context.clone(), block_verifier.clone(), dag_state.clone());
1242 let round_tracker = Arc::new(RwLock::new(RoundTracker::new(context.clone(), vec![])));
1243 let peers_pool = Arc::new(PeersPool::new(context.clone()));
1244 let synchronizer = Synchronizer::start(
1245 network_client,
1246 context.clone(),
1247 core_dispatcher.clone(),
1248 commit_vote_monitor.clone(),
1249 block_verifier.clone(),
1250 transaction_vote_tracker.clone(),
1251 round_tracker.clone(),
1252 dag_state.clone(),
1253 peers_pool.clone(),
1254 true,
1255 );
1256 let block_sync_service = Arc::new(BlockSyncService::new(
1257 context.clone(),
1258 dag_state.clone(),
1259 store.clone(),
1260 ));
1261 let authority_service = Arc::new(AuthorityService::new(
1262 context.clone(),
1263 block_verifier,
1264 commit_vote_monitor,
1265 round_tracker,
1266 synchronizer,
1267 core_dispatcher.clone(),
1268 rx_block_broadcast,
1269 transaction_vote_tracker,
1270 dag_state.clone(),
1271 block_sync_service,
1272 ));
1273
1274 let mut dag_builder = DagBuilder::new(context.clone());
1276 dag_builder
1277 .layers(1..=10)
1278 .authorities(vec![AuthorityIndex::new_for_test(2)])
1279 .equivocate(1)
1280 .build()
1281 .persist_layers(dag_state);
1282
1283 let authorities_to_request = vec![
1285 AuthorityIndex::new_for_test(1),
1286 AuthorityIndex::new_for_test(2),
1287 ];
1288 let results = authority_service
1289 .handle_fetch_latest_blocks(AuthorityIndex::new_for_test(1), authorities_to_request)
1290 .await;
1291
1292 let serialised_blocks = results.unwrap();
1294 for serialised_block in serialised_blocks {
1295 let signed_block: SignedBlock =
1296 bcs::from_bytes(&serialised_block).expect("Error while deserialising block");
1297 let verified_block = VerifiedBlock::new_verified(signed_block, serialised_block);
1298
1299 assert_eq!(verified_block.round(), 10);
1300 }
1301 }
1302
1303 #[tokio::test(flavor = "current_thread", start_paused = true)]
1304 async fn test_handle_subscribe_blocks() {
1305 let (context, _keys) = Context::new_for_test(4);
1306 let context = Arc::new(context);
1307 let block_verifier = Arc::new(crate::block_verifier::NoopBlockVerifier {});
1308 let commit_vote_monitor = Arc::new(CommitVoteMonitor::new(context.clone()));
1309 let core_dispatcher = Arc::new(FakeCoreThreadDispatcher::new());
1310 let (_tx_block_broadcast, rx_block_broadcast) = broadcast::channel(100);
1311 let fake_client = Arc::new(FakeNetworkClient::default());
1312 let network_client = Arc::new(SynchronizerClient::new(
1313 context.clone(),
1314 Some(fake_client.clone()),
1315 Some(fake_client.clone()),
1316 ));
1317 let store = Arc::new(MemStore::new());
1318 let dag_state = Arc::new(RwLock::new(DagState::new(context.clone(), store.clone())));
1319 let transaction_vote_tracker =
1320 TransactionVoteTracker::new(context.clone(), block_verifier.clone(), dag_state.clone());
1321 let round_tracker = Arc::new(RwLock::new(RoundTracker::new(context.clone(), vec![])));
1322 let peers_pool = Arc::new(PeersPool::new(context.clone()));
1323 let synchronizer = Synchronizer::start(
1324 network_client,
1325 context.clone(),
1326 core_dispatcher.clone(),
1327 commit_vote_monitor.clone(),
1328 block_verifier.clone(),
1329 transaction_vote_tracker.clone(),
1330 round_tracker.clone(),
1331 dag_state.clone(),
1332 peers_pool.clone(),
1333 false,
1334 );
1335 let block_sync_service = Arc::new(BlockSyncService::new(
1336 context.clone(),
1337 dag_state.clone(),
1338 store.clone(),
1339 ));
1340
1341 dag_state
1343 .write()
1344 .accept_block(VerifiedBlock::new_for_test(TestBlock::new(5, 0).build()));
1345 dag_state
1346 .write()
1347 .accept_block(VerifiedBlock::new_for_test(TestBlock::new(10, 0).build()));
1348 dag_state
1349 .write()
1350 .accept_block(VerifiedBlock::new_for_test(TestBlock::new(15, 0).build()));
1351
1352 let authority_service = Arc::new(AuthorityService::new(
1353 context.clone(),
1354 block_verifier,
1355 commit_vote_monitor,
1356 round_tracker,
1357 synchronizer,
1358 core_dispatcher.clone(),
1359 rx_block_broadcast,
1360 transaction_vote_tracker,
1361 dag_state.clone(),
1362 block_sync_service,
1363 ));
1364
1365 let peer = context.committee.to_authority_index(1).unwrap();
1366
1367 {
1370 let mut stream = authority_service
1371 .handle_subscribe_blocks(peer, 100)
1372 .await
1373 .unwrap();
1374 let block: SignedBlock = bcs::from_bytes(&stream.next().await.unwrap().block).unwrap();
1375 assert_eq!(
1376 block.round(),
1377 15,
1378 "Should return last proposed block as fallback"
1379 );
1380 assert_eq!(block.author().value(), 0);
1381 }
1382
1383 {
1386 let mut stream = authority_service
1387 .handle_subscribe_blocks(peer, 7)
1388 .await
1389 .unwrap();
1390
1391 let block1: SignedBlock = bcs::from_bytes(&stream.next().await.unwrap().block).unwrap();
1392 assert_eq!(block1.round(), 10, "Should return block at round 10");
1393
1394 let block2: SignedBlock = bcs::from_bytes(&stream.next().await.unwrap().block).unwrap();
1395 assert_eq!(block2.round(), 15, "Should return block at round 15");
1396 }
1397 }
1398
1399 #[tokio::test(flavor = "current_thread", start_paused = true)]
1400 async fn test_handle_subscribe_blocks_not_proposed() {
1401 let (context, _keys) = Context::new_for_test(4);
1402 let context = Arc::new(context);
1403 let block_verifier = Arc::new(crate::block_verifier::NoopBlockVerifier {});
1404 let commit_vote_monitor = Arc::new(CommitVoteMonitor::new(context.clone()));
1405 let core_dispatcher = Arc::new(FakeCoreThreadDispatcher::new());
1406 let (_tx_block_broadcast, rx_block_broadcast) = broadcast::channel(100);
1407 let fake_client = Arc::new(FakeNetworkClient::default());
1408 let network_client = Arc::new(SynchronizerClient::new(
1409 context.clone(),
1410 Some(fake_client.clone()),
1411 Some(fake_client.clone()),
1412 ));
1413 let store = Arc::new(MemStore::new());
1414 let dag_state = Arc::new(RwLock::new(DagState::new(context.clone(), store.clone())));
1415 let transaction_vote_tracker =
1416 TransactionVoteTracker::new(context.clone(), block_verifier.clone(), dag_state.clone());
1417 let round_tracker = Arc::new(RwLock::new(RoundTracker::new(context.clone(), vec![])));
1418 let peers_pool = Arc::new(PeersPool::new(context.clone()));
1419 let synchronizer = Synchronizer::start(
1420 network_client,
1421 context.clone(),
1422 core_dispatcher.clone(),
1423 commit_vote_monitor.clone(),
1424 block_verifier.clone(),
1425 transaction_vote_tracker.clone(),
1426 round_tracker.clone(),
1427 dag_state.clone(),
1428 peers_pool.clone(),
1429 false,
1430 );
1431 let block_sync_service = Arc::new(BlockSyncService::new(
1432 context.clone(),
1433 dag_state.clone(),
1434 store.clone(),
1435 ));
1436
1437 let authority_service = Arc::new(AuthorityService::new(
1440 context.clone(),
1441 block_verifier,
1442 commit_vote_monitor,
1443 round_tracker,
1444 synchronizer,
1445 core_dispatcher.clone(),
1446 rx_block_broadcast,
1447 transaction_vote_tracker,
1448 dag_state.clone(),
1449 block_sync_service,
1450 ));
1451
1452 let peer = context.committee.to_authority_index(1).unwrap();
1453
1454 let mut stream = authority_service
1456 .handle_subscribe_blocks(peer, 0)
1457 .await
1458 .unwrap();
1459
1460 use futures::poll;
1462 use std::task::Poll;
1463 let poll_result = poll!(stream.next());
1464 assert!(
1465 matches!(poll_result, Poll::Pending),
1466 "Should not receive genesis block on subscription stream"
1467 );
1468 }
1469}