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