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