1use std::{
5 sync::{Arc, Weak},
6 time::{Duration, Instant},
7};
8
9use consensus_config::{
10 Committee, ConsensusProtocolConfig, NetworkKeyPair, NetworkPublicKey, Parameters,
11 ProtocolKeyPair,
12};
13use consensus_types::block::Round;
14use itertools::Itertools;
15use mysten_common::debug_fatal;
16use mysten_network::Multiaddr;
17use parking_lot::RwLock;
18use prometheus::Registry;
19use tracing::{info, warn};
20
21use crate::{
22 BlockAPI as _, CommitConsumerArgs, RandomnessSignatureHandler,
23 authority_service::AuthorityService,
24 block_manager::BlockManager,
25 block_sync_service::BlockSyncService,
26 block_verifier::SignedBlockVerifier,
27 commit_observer::CommitObserver,
28 commit_syncer::{CommitSyncer, CommitSyncerHandle},
29 commit_vote_monitor::CommitVoteMonitor,
30 context::{Clock, Context},
31 core::{Core, CoreSignals},
32 core_thread::{ChannelCoreThreadDispatcher, CoreThreadHandle},
33 dag_state::DagState,
34 leader_schedule::LeaderSchedule,
35 leader_timeout::{LeaderTimeoutTask, LeaderTimeoutTaskHandle},
36 metrics::initialise_metrics,
37 network::{
38 CommitSyncerClient, NetworkManager, PeerId, SynchronizerClient, tonic_network::TonicManager,
39 },
40 observer_service::ObserverService,
41 observer_subscriber::ObserverSubscriber,
42 peers_pool::PeersPool,
43 round_prober::{RoundProber, RoundProberHandle},
44 round_tracker::RoundTracker,
45 storage::rocksdb_store::RocksDBStore,
46 subscriber::Subscriber,
47 synchronizer::{Synchronizer, SynchronizerHandle},
48 transaction::{
49 TransactionClient, TransactionConsumer, TransactionConsumerPool, TransactionPool,
50 TransactionVerifier,
51 },
52 transaction_vote_tracker::TransactionVoteTracker,
53};
54
55#[allow(private_interfaces)]
58pub enum ConsensusAuthority {
59 WithTonic(AuthorityNode<TonicManager>),
60}
61
62impl ConsensusAuthority {
63 pub async fn start(
64 network_type: NetworkType,
65 epoch_start_timestamp_ms: u64,
66 committee: Committee,
67 parameters: Parameters,
68 protocol_config: ConsensusProtocolConfig,
69 protocol_keypair: Option<ProtocolKeyPair>,
71 network_keypair: NetworkKeyPair,
72 clock: Arc<Clock>,
73 transaction_verifier: Arc<dyn TransactionVerifier>,
74 transaction_pool: Option<Arc<dyn TransactionPool>>,
77 commit_consumer: CommitConsumerArgs,
78 registry: Registry,
79 boot_counter: u64,
83 randomness_signature_handler: Option<Arc<dyn RandomnessSignatureHandler>>,
84 ) -> Self {
85 match network_type {
86 NetworkType::Tonic => {
87 let authority = AuthorityNode::start(
88 epoch_start_timestamp_ms,
89 committee,
90 parameters,
91 protocol_config,
92 protocol_keypair,
93 network_keypair,
94 clock,
95 transaction_verifier,
96 transaction_pool,
97 commit_consumer,
98 registry,
99 boot_counter,
100 randomness_signature_handler,
101 )
102 .await;
103 Self::WithTonic(authority)
104 }
105 }
106 }
107
108 pub async fn stop(self) {
109 match self {
110 Self::WithTonic(authority) => authority.stop().await,
111 }
112 }
113
114 pub fn update_peer_address(
115 &self,
116 network_pubkey: NetworkPublicKey,
117 address: Option<Multiaddr>,
118 ) {
119 match self {
120 Self::WithTonic(authority) => authority.update_peer_address(network_pubkey, address),
121 }
122 }
123
124 pub fn transaction_client(&self) -> Arc<TransactionClient> {
125 match self {
126 Self::WithTonic(authority) => authority.transaction_client(),
127 }
128 }
129
130 pub fn store(&self) -> Arc<RocksDBStore> {
131 match self {
132 Self::WithTonic(authority) => authority.store(),
133 }
134 }
135
136 #[cfg(test)]
137 fn context(&self) -> &Arc<Context> {
138 match self {
139 Self::WithTonic(authority) => &authority.context,
140 }
141 }
142}
143
144#[derive(Clone, Copy, PartialEq, Eq, Debug)]
145pub enum NetworkType {
146 Tonic,
147}
148
149enum SubscriberType<N: NetworkManager> {
151 Validator(Subscriber<N::ValidatorClient, AuthorityService<ChannelCoreThreadDispatcher>>),
152 Observer(ObserverSubscriber<N::ObserverClient, ObserverService>),
153}
154
155impl<N: NetworkManager> SubscriberType<N> {
156 async fn stop(&self) {
157 match self {
158 SubscriberType::Validator(subscriber) => subscriber.stop().await,
159 SubscriberType::Observer(subscriber) => subscriber.stop().await,
160 }
161 }
162}
163
164pub(crate) struct AuthorityNode<N>
165where
166 N: NetworkManager,
167{
168 context: Arc<Context>,
169 start_time: Instant,
170 transaction_client: Arc<TransactionClient>,
171 synchronizer: Arc<SynchronizerHandle>,
172 store: Arc<RocksDBStore>,
173 dag_state: Weak<RwLock<DagState>>,
176
177 commit_syncer_handle: CommitSyncerHandle,
178 round_prober_handle: Option<RoundProberHandle>,
179 leader_timeout_handle: LeaderTimeoutTaskHandle,
180 core_thread_handle: CoreThreadHandle,
181 subscriber: SubscriberType<N>,
182 observer_service: Option<Arc<ObserverService>>,
185 network_manager: N,
186}
187
188impl<N> AuthorityNode<N>
189where
190 N: NetworkManager,
191{
192 pub(crate) async fn start(
194 epoch_start_timestamp_ms: u64,
195 committee: Committee,
196 parameters: Parameters,
197 protocol_config: ConsensusProtocolConfig,
198 protocol_keypair: Option<ProtocolKeyPair>,
199 network_keypair: NetworkKeyPair,
200 clock: Arc<Clock>,
201 transaction_verifier: Arc<dyn TransactionVerifier>,
202 transaction_pool: Option<Arc<dyn TransactionPool>>,
203 commit_consumer: CommitConsumerArgs,
204 registry: Registry,
205 boot_counter: u64,
206 randomness_signature_handler: Option<Arc<dyn RandomnessSignatureHandler>>,
207 ) -> Self {
208 let metrics = initialise_metrics(registry);
209
210 let own_index = if let Some(protocol_keypair) = &protocol_keypair {
212 let (own_index, _) = committee
213 .authorities()
214 .find(|(_, a)| a.protocol_key == protocol_keypair.public())
215 .expect("Own authority should be among the consensus authorities!");
216
217 let own_hostname = committee.authority(own_index).hostname.clone();
218 info!(
219 "Starting consensus validator authority {} {}, {:?}, epoch start timestamp {}, boot counter {}, replaying after commit index {}, consumer last processed commit index {}",
220 own_index,
221 own_hostname,
222 protocol_config.protocol_version(),
223 epoch_start_timestamp_ms,
224 boot_counter,
225 commit_consumer.replay_after_commit_index,
226 commit_consumer.consumer_last_processed_commit_index
227 );
228
229 metrics
230 .node_metrics
231 .authority_index
232 .with_label_values(&[&own_hostname])
233 .set(own_index.value() as i64);
234 Some(own_index)
235 } else {
236 info!(
238 "Starting consensus observer authority, {:?}, epoch start timestamp {}, boot counter {}, replaying after commit index {}, consumer last processed commit index {}",
239 protocol_config.protocol_version(),
240 epoch_start_timestamp_ms,
241 boot_counter,
242 commit_consumer.replay_after_commit_index,
243 commit_consumer.consumer_last_processed_commit_index
244 );
245 None
246 };
247
248 info!(
249 "Consensus authorities: {}",
250 committee
251 .authorities()
252 .map(|(i, a)| format!("{}: {}", i, a.hostname))
253 .join(", ")
254 );
255 info!("Consensus parameters: {:?}", parameters);
256 info!("Consensus committee: {:?}", committee);
257 let context = Arc::new(Context::new(
258 epoch_start_timestamp_ms,
259 own_index,
260 committee,
261 parameters,
262 protocol_config,
263 metrics,
264 clock,
265 ));
266 let start_time = Instant::now();
267
268 context
269 .metrics
270 .node_metrics
271 .protocol_version
272 .set(context.protocol_config.protocol_version() as i64);
273
274 let (tx_client, tx_receiver, priority_tx_receiver) =
275 TransactionClient::new(context.clone());
276 let transaction_pool: Arc<dyn TransactionPool> = match transaction_pool {
277 Some(pool) => {
281 drop(tx_receiver);
282 drop(priority_tx_receiver);
283 pool
284 }
285 None => Arc::new(TransactionConsumerPool::new(TransactionConsumer::new(
286 tx_receiver,
287 priority_tx_receiver,
288 context.clone(),
289 ))),
290 };
291
292 let (core_signals, signals_receivers) = CoreSignals::new(context.clone());
293
294 let mut network_manager = N::new(context.clone(), network_keypair);
295 let validator_client = network_manager.validator_client();
296 let observer_client = network_manager.observer_client();
297
298 let synchronizer_client = Arc::new(SynchronizerClient::<
299 N::ValidatorClient,
300 N::ObserverClient,
301 >::new(
302 context.clone(),
303 Some(validator_client.clone()),
304 Some(observer_client.clone()),
305 ));
306 let commit_syncer_client = Arc::new(CommitSyncerClient::<
307 N::ValidatorClient,
308 N::ObserverClient,
309 >::new(
310 context.clone(),
311 Some(validator_client.clone()),
312 Some(observer_client.clone()),
313 ));
314
315 let store_path = context.parameters.db_path.as_path().to_str().unwrap();
316 let store = Arc::new(RocksDBStore::new(store_path));
317 let dag_state = Arc::new(RwLock::new(DagState::new(context.clone(), store.clone())));
318
319 let block_verifier = Arc::new(SignedBlockVerifier::new(
320 context.clone(),
321 transaction_verifier,
322 ));
323
324 let transaction_vote_tracker =
325 TransactionVoteTracker::new(context.clone(), block_verifier.clone(), dag_state.clone());
326
327 let sync_last_known_own_block = boot_counter == 0
329 && !context
330 .parameters
331 .sync_last_known_own_block_timeout
332 .is_zero()
333 && context.is_validator();
334 info!(
335 "Sync last known own block: {}. Boot count: {}. Timeout: {:?}.",
336 sync_last_known_own_block,
337 boot_counter,
338 context.parameters.sync_last_known_own_block_timeout
339 );
340
341 let block_manager = BlockManager::new(context.clone(), dag_state.clone());
342
343 let leader_schedule = Arc::new(LeaderSchedule::from_store(
344 context.clone(),
345 dag_state.clone(),
346 ));
347
348 let commit_consumer_monitor = commit_consumer.monitor();
349 let commit_observer = CommitObserver::new(
350 context.clone(),
351 commit_consumer,
352 dag_state.clone(),
353 transaction_vote_tracker.clone(),
354 )
355 .await;
356
357 let initial_received_rounds = dag_state
358 .read()
359 .get_last_cached_block_per_authority(Round::MAX)
360 .into_iter()
361 .map(|(block, _)| block.round())
362 .collect::<Vec<_>>();
363 let round_tracker = Arc::new(RwLock::new(RoundTracker::new(
364 context.clone(),
365 initial_received_rounds,
366 )));
367
368 let core = if context.is_validator() {
371 Core::new_validator(
372 context.clone(),
373 leader_schedule,
374 transaction_pool,
375 transaction_vote_tracker.clone(),
376 block_manager,
377 commit_observer,
378 core_signals,
379 protocol_keypair.expect("protocol keypair is required when running as validator"),
380 dag_state.clone(),
381 sync_last_known_own_block,
382 round_tracker.clone(),
383 )
384 } else {
385 Core::new_observer(
386 context.clone(),
387 leader_schedule,
388 block_manager,
389 commit_observer,
390 core_signals,
391 dag_state.clone(),
392 )
393 };
394
395 let (core_dispatcher, core_thread_handle) =
396 ChannelCoreThreadDispatcher::start(context.clone(), &dag_state, core);
397 let core_dispatcher = Arc::new(core_dispatcher);
398 let leader_timeout_handle =
399 LeaderTimeoutTask::start(core_dispatcher.clone(), &signals_receivers, context.clone());
400
401 let commit_vote_monitor = Arc::new(CommitVoteMonitor::new(context.clone()));
402
403 let peers_pool = Arc::new(PeersPool::new(context.clone()));
405
406 let synchronizer = Synchronizer::start(
407 synchronizer_client.clone(),
408 context.clone(),
409 core_dispatcher.clone(),
410 commit_vote_monitor.clone(),
411 block_verifier.clone(),
412 transaction_vote_tracker.clone(),
413 round_tracker.clone(),
414 dag_state.clone(),
415 peers_pool.clone(),
416 sync_last_known_own_block,
417 );
418
419 let commit_syncer_handle = CommitSyncer::new(
420 context.clone(),
421 core_dispatcher.clone(),
422 commit_vote_monitor.clone(),
423 commit_consumer_monitor.clone(),
424 block_verifier.clone(),
425 transaction_vote_tracker.clone(),
426 round_tracker.clone(),
427 commit_syncer_client.clone(),
428 dag_state.clone(),
429 peers_pool.clone(),
430 )
431 .start();
432
433 let block_sync_service = Arc::new(BlockSyncService::new(
435 context.clone(),
436 dag_state.clone(),
437 store.clone(),
438 ));
439
440 let (subscriber, round_prober_handle, observer_service) = if context.is_validator() {
441 let authority_service = Arc::new(AuthorityService::new(
442 context.clone(),
443 block_verifier.clone(),
444 commit_vote_monitor.clone(),
445 round_tracker.clone(),
446 synchronizer.clone(),
447 core_dispatcher.clone(),
448 signals_receivers.block_broadcast_receiver(),
449 transaction_vote_tracker.clone(),
450 dag_state.clone(),
451 block_sync_service.clone(),
452 ));
453
454 network_manager
456 .start_validator_server(authority_service.clone())
457 .await;
458
459 let s = Subscriber::new(
461 context.clone(),
462 validator_client.clone(),
463 authority_service.clone(),
464 dag_state.clone(),
465 );
466 for (peer, _) in context.committee.authorities() {
467 if peer != context.own_index {
468 s.subscribe(peer);
469 }
470 }
471
472 let round_prober_handle = Some(
474 RoundProber::new(
475 context.clone(),
476 core_dispatcher.clone(),
477 round_tracker.clone(),
478 dag_state.clone(),
479 validator_client,
480 )
481 .start(),
482 );
483
484 let observer_service = if context.parameters.observer.is_server_enabled() {
486 let observer_service = Arc::new(ObserverService::new(
487 context.clone(),
488 core_dispatcher.clone(),
489 dag_state.clone(),
490 signals_receivers.accepted_block_broadcast_receiver(),
491 block_verifier,
492 commit_vote_monitor.clone(),
493 transaction_vote_tracker.clone(),
494 synchronizer.clone(),
495 block_sync_service.clone(),
496 randomness_signature_handler.clone(),
497 ));
498 network_manager
499 .start_observer_server(observer_service.clone())
500 .await;
501 Some(observer_service)
502 } else {
503 None
504 };
505
506 (
507 SubscriberType::Validator(s),
508 round_prober_handle,
509 observer_service,
510 )
511 } else {
512 let observer_client = network_manager.observer_client();
514 let observer_service = Arc::new(ObserverService::new(
515 context.clone(),
516 core_dispatcher.clone(),
517 dag_state.clone(),
518 signals_receivers.accepted_block_broadcast_receiver(),
519 block_verifier,
520 commit_vote_monitor.clone(),
521 transaction_vote_tracker.clone(),
522 synchronizer.clone(),
523 block_sync_service.clone(),
524 randomness_signature_handler.clone(),
525 ));
526
527 let observer_subscriber = ObserverSubscriber::new(
528 context.clone(),
529 observer_client,
530 observer_service.clone(),
531 commit_vote_monitor.clone(),
532 dag_state.clone(),
533 randomness_signature_handler,
534 );
535
536 network_manager
537 .start_observer_server(observer_service.clone())
538 .await;
539
540 for peer_record in context.parameters.observer.peers.iter().take(1) {
544 let peer_id = if let Some((index, _)) = context
545 .committee
546 .authorities()
547 .find(|(_, authority)| authority.network_key == peer_record.public_key)
548 {
549 PeerId::Validator(index)
550 } else {
551 PeerId::Observer(Box::new(peer_record.public_key.clone()))
552 };
553
554 info!("Observer subscribing to peer: {:?}", peer_id);
555 observer_subscriber.subscribe(peer_id);
556 }
557
558 (
559 SubscriberType::Observer(observer_subscriber),
560 None,
561 Some(observer_service),
562 )
563 };
564
565 info!(
566 "Consensus authority started, took {:?}",
567 start_time.elapsed()
568 );
569
570 Self {
571 context,
572 start_time,
573 transaction_client: Arc::new(tx_client),
574 synchronizer,
575 store,
576 dag_state: Arc::downgrade(&dag_state),
577 commit_syncer_handle,
578 round_prober_handle,
579 leader_timeout_handle,
580 core_thread_handle,
581 subscriber,
582 observer_service,
583 network_manager,
584 }
585 }
586
587 pub(crate) async fn stop(self) {
588 let Self {
589 context,
590 start_time,
591 transaction_client,
592 synchronizer,
593 store,
594 dag_state,
595 commit_syncer_handle,
596 round_prober_handle,
597 leader_timeout_handle,
598 core_thread_handle,
599 subscriber,
600 observer_service,
601 mut network_manager,
602 } = self;
603
604 info!(
605 "Stopping authority. Total run time: {:?}",
606 start_time.elapsed()
607 );
608
609 synchronizer.stop().await;
611 commit_syncer_handle.stop().await;
612 if let Some(round_prober_handle) = round_prober_handle {
613 round_prober_handle.stop().await;
614 }
615 leader_timeout_handle.stop().await;
616 core_thread_handle.stop().await;
618 subscriber.stop().await;
620 network_manager.stop().await;
621
622 context
623 .metrics
624 .node_metrics
625 .uptime
626 .observe(start_time.elapsed().as_secs_f64());
627
628 drop((
629 context,
630 transaction_client,
631 synchronizer,
632 store,
633 subscriber,
634 observer_service,
635 network_manager,
636 ));
637
638 let mut dag_state_owners = dag_state.strong_count();
645 for _ in 0..5 {
646 if dag_state_owners == 0 {
647 break;
648 }
649 tokio::time::sleep(Duration::from_millis(1)).await;
650 dag_state_owners = dag_state.strong_count();
651 }
652 if dag_state_owners != 0 {
653 debug_fatal!(
654 "DagState still has {} owner(s) after stopping ConsensusAuthority",
655 dag_state_owners
656 );
657 }
658 }
659
660 pub(crate) fn transaction_client(&self) -> Arc<TransactionClient> {
661 self.transaction_client.clone()
662 }
663
664 pub(crate) fn store(&self) -> Arc<RocksDBStore> {
665 self.store.clone()
666 }
667
668 pub(crate) fn update_peer_address(
669 &self,
670 network_pubkey: NetworkPublicKey,
671 address: Option<Multiaddr>,
672 ) {
673 let Some(peer) = self
675 .context
676 .committee
677 .authorities()
678 .find(|(_, authority)| authority.network_key == network_pubkey)
679 .map(|(index, _)| index)
680 else {
681 warn!(
682 "Network public key {:?} not found in committee, ignoring address update",
683 network_pubkey
684 );
685 return;
686 };
687
688 self.network_manager.update_peer_address(peer, address);
690
691 if peer != self.context.own_index {
693 info!("Re-subscribing to peer {} after address update", peer);
694 match &self.subscriber {
695 SubscriberType::Validator(s) => s.subscribe(peer),
696 SubscriberType::Observer(s) => {
697 s.subscribe(PeerId::Validator(peer));
699 }
700 }
701 }
702 }
703}
704
705#[cfg(test)]
706mod tests {
707 #![allow(non_snake_case)]
708
709 use std::{
710 collections::{BTreeMap, BTreeSet},
711 sync::Arc,
712 time::Duration,
713 };
714
715 use consensus_config::{
716 AuthorityIndex, ObserverParameters, Parameters, PeerRecord, local_committee_and_keys,
717 };
718 use mysten_metrics::RegistryService;
719 use mysten_metrics::monitored_mpsc::UnboundedReceiver;
720 use prometheus::Registry;
721 use rand::{SeedableRng, rngs::StdRng};
722 use rstest::rstest;
723 use tempfile::TempDir;
724 use tokio::time::{sleep, timeout};
725 use typed_store::DBMetrics;
726
727 use super::*;
728 use crate::{
729 CommittedSubDag,
730 block::{BlockAPI as _, GENESIS_ROUND},
731 transaction::{NoopTransactionVerifier, Priority},
732 };
733
734 #[rstest]
735 #[tokio::test]
736 async fn test_authority_start_and_stop(
737 #[values(NetworkType::Tonic)] network_type: NetworkType,
738 ) {
739 let (committee, keypairs) = local_committee_and_keys(0, vec![1]);
740 let registry = Registry::new();
741
742 let temp_dir = TempDir::new().unwrap();
743 let parameters = Parameters {
744 db_path: temp_dir.keep(),
745 ..Default::default()
746 };
747 let txn_verifier = NoopTransactionVerifier {};
748
749 let own_index = committee.to_authority_index(0).unwrap();
750 let protocol_keypair = keypairs[own_index].1.clone();
751 let network_keypair = keypairs[own_index].0.clone();
752
753 let (commit_consumer, _) = CommitConsumerArgs::new(0, 0);
754
755 let authority = ConsensusAuthority::start(
756 network_type,
757 0,
758 committee,
759 parameters,
760 ConsensusProtocolConfig::for_testing(),
761 Some(protocol_keypair),
762 network_keypair,
763 Arc::new(Clock::default()),
764 Arc::new(txn_verifier),
765 None,
766 commit_consumer,
767 registry,
768 0,
769 None,
770 )
771 .await;
772
773 assert_eq!(authority.context().own_index, own_index);
774 assert_eq!(authority.context().committee.epoch(), 0);
775 assert_eq!(authority.context().committee.size(), 1);
776
777 authority.stop().await;
778 }
779
780 #[rstest]
781 #[tokio::test]
782 async fn test_observer_start_and_stop(#[values(NetworkType::Tonic)] network_type: NetworkType) {
783 let (committee, keypairs) = local_committee_and_keys(0, vec![1]);
784 let registry = Registry::new();
785
786 let temp_dir = TempDir::new().unwrap();
787 let parameters = Parameters {
788 db_path: temp_dir.keep(),
789 ..Default::default()
790 };
791 let txn_verifier = NoopTransactionVerifier {};
792
793 let network_keypair = keypairs[0].0.clone();
795
796 let (commit_consumer, _) = CommitConsumerArgs::new(0, 0);
797
798 let observer = ConsensusAuthority::start(
799 network_type,
800 0,
801 committee.clone(),
802 parameters,
803 ConsensusProtocolConfig::for_testing(),
804 None, network_keypair,
806 Arc::new(Clock::default()),
807 Arc::new(txn_verifier),
808 None,
809 commit_consumer,
810 registry,
811 0,
812 None,
813 )
814 .await;
815
816 sleep(Duration::from_secs(2)).await;
817
818 assert_eq!(observer.context().own_index, AuthorityIndex::MAX);
820 assert_eq!(observer.context().committee.epoch(), 0);
821 assert_eq!(observer.context().committee.size(), 1);
822 assert!(!observer.context().is_validator());
823
824 observer.stop().await;
825 }
826
827 #[rstest]
832 #[tokio::test(flavor = "current_thread")]
833 async fn test_authority_committee(
834 #[values(NetworkType::Tonic)] network_type: NetworkType,
835 #[values(5, 10)] gc_depth: u32,
836 ) {
837 telemetry_subscribers::init_for_testing();
838 let db_registry = Registry::new();
839 DBMetrics::init(RegistryService::new(db_registry));
840
841 const NUM_OF_AUTHORITIES: usize = 4;
842 let (committee, keypairs) = local_committee_and_keys(0, [1; NUM_OF_AUTHORITIES].to_vec());
843 let mut protocol_config = ConsensusProtocolConfig::for_testing();
844 protocol_config.set_gc_depth_for_testing(gc_depth);
845
846 let temp_dirs = (0..NUM_OF_AUTHORITIES)
847 .map(|_| TempDir::new().unwrap())
848 .collect::<Vec<_>>();
849
850 let mut commit_receivers = Vec::with_capacity(committee.size());
851 let mut authorities = Vec::with_capacity(committee.size());
852 let mut boot_counters = [0; NUM_OF_AUTHORITIES];
853
854 let observer_server_port = 8900 + gc_depth as u16;
856
857 let mut authority_0_network_key = None;
859 for (index, authority_info) in committee.authorities() {
860 let (authority, commit_receiver) = if index.value() == 0 {
861 authority_0_network_key = Some(authority_info.network_key.clone());
863 make_authority_with_observer_server(
865 index,
866 &temp_dirs[index.value()],
867 committee.clone(),
868 keypairs.clone(),
869 network_type,
870 boot_counters[index],
871 protocol_config.clone(),
872 Some(observer_server_port),
873 )
874 .await
875 } else {
876 make_authority(
877 index,
878 &temp_dirs[index.value()],
879 committee.clone(),
880 keypairs.clone(),
881 network_type,
882 boot_counters[index],
883 protocol_config.clone(),
884 )
885 .await
886 };
887 boot_counters[index] += 1;
888 commit_receivers.push(commit_receiver);
889 authorities.push(authority);
890 }
891
892 let observer_temp_dir = TempDir::new().unwrap();
894 let mut rng = StdRng::from_seed([99; 32]);
895 let observer_network_keypair = consensus_config::NetworkKeyPair::generate(&mut rng);
896
897 let observer_parameters = Parameters {
898 db_path: observer_temp_dir.path().to_path_buf(),
899 observer: ObserverParameters {
900 peers: vec![PeerRecord {
902 public_key: authority_0_network_key
903 .clone()
904 .expect("Authority 0 network key should be set"),
905 address: format!("/ip4/127.0.0.1/udp/{}", observer_server_port)
906 .parse()
907 .unwrap(),
908 }],
909 ..Default::default()
910 },
911 ..Default::default()
912 };
913
914 let (observer_commit_consumer, observer_commit_receiver) = CommitConsumerArgs::new(0, 0);
915 let observer = ConsensusAuthority::start(
916 network_type,
917 0,
918 committee.clone(),
919 observer_parameters,
920 protocol_config.clone(),
921 None, observer_network_keypair,
923 Arc::new(Clock::default()),
924 Arc::new(NoopTransactionVerifier {}),
925 None,
926 observer_commit_consumer,
927 Registry::new(),
928 0,
929 None,
930 )
931 .await;
932 commit_receivers.push(observer_commit_receiver);
935
936 sleep(Duration::from_secs(5)).await;
938
939 const NUM_TRANSACTIONS: u8 = 15;
940 let mut submitted_transactions = BTreeSet::<Vec<u8>>::new();
941 for i in 0..NUM_TRANSACTIONS {
942 let txn = vec![i; 16];
943 submitted_transactions.insert(txn.clone());
944 authorities[i as usize % authorities.len()]
945 .transaction_client()
946 .submit(vec![txn], Priority::Normal)
947 .await
948 .unwrap();
949 }
950
951 for receiver in &mut commit_receivers {
952 let mut expected_transactions = submitted_transactions.clone();
953 loop {
954 let committed_subdag =
955 tokio::time::timeout(Duration::from_secs(1), receiver.recv())
956 .await
957 .unwrap()
958 .unwrap();
959 for b in committed_subdag.blocks {
960 for txn in b.transactions().iter().map(|t| t.data().to_vec()) {
961 assert!(
962 expected_transactions.remove(&txn),
963 "Transaction not submitted or already seen: {:?}",
964 txn
965 );
966 }
967 }
968 if expected_transactions.is_empty() {
969 break;
970 }
971 }
972 }
973
974 let index = committee.to_authority_index(1).unwrap();
976 authorities.remove(index.value()).stop().await;
977 sleep(Duration::from_secs(10)).await;
978
979 let (authority, commit_receiver) = make_authority(
981 index,
982 &temp_dirs[index.value()],
983 committee.clone(),
984 keypairs.clone(),
985 network_type,
986 boot_counters[index],
987 protocol_config.clone(),
988 )
989 .await;
990 boot_counters[index] += 1;
991 commit_receivers[index] = commit_receiver;
992 authorities.insert(index.value(), authority);
993 sleep(Duration::from_secs(10)).await;
994
995 let observer_context = observer.context();
1000 assert!(
1001 observer_context.is_observer(),
1002 "It should be an observer node"
1003 );
1004
1005 let authority_0 = &authorities[0];
1007 let authority_0_context = authority_0.context();
1008 let mut authority_0_total_verified_blocks = 0;
1009
1010 for (_, authority_info) in committee.authorities() {
1012 if let Ok(metric) = authority_0_context
1013 .metrics
1014 .node_metrics
1015 .verified_blocks
1016 .get_metric_with_label_values(&[&authority_info.hostname])
1017 {
1018 authority_0_total_verified_blocks += metric.get();
1019 println!(
1020 "authority_info.hostname: {}, metric: {:?}",
1021 authority_info.hostname, authority_0_total_verified_blocks
1022 );
1023 }
1024 }
1025
1026 let mut authority_0_total_proposed_blocks = 0;
1027 for force in [true, false] {
1028 if let Ok(metric) = authority_0_context
1029 .metrics
1030 .node_metrics
1031 .proposed_blocks
1032 .get_metric_with_label_values(&[&force.to_string()])
1033 {
1034 authority_0_total_proposed_blocks += metric.get();
1035 }
1036 }
1037
1038 authority_0_total_verified_blocks += authority_0_total_proposed_blocks;
1039
1040 let mut observer_received_blocks = 0;
1042 for (_, authority_info) in committee.authorities() {
1043 if let Ok(metric) = observer_context
1044 .metrics
1045 .node_metrics
1046 .verified_blocks
1047 .get_metric_with_label_values(&[&authority_info.hostname])
1048 {
1049 observer_received_blocks += metric.get();
1050 }
1051 }
1052
1053 assert!(
1056 observer_received_blocks > 0,
1057 "Observer should have received at least some blocks, got: {}",
1058 observer_received_blocks
1059 );
1060
1061 println!(
1062 "authority_0_total_verified_blocks: {}, observer_received_blocks: {}",
1063 authority_0_total_verified_blocks, observer_received_blocks
1064 );
1065
1066 const TOLERANCE: u64 = 20;
1067 assert!(
1068 authority_0_total_verified_blocks - observer_received_blocks <= TOLERANCE,
1069 "The number of blocks received by the observer ({}) should be close to the number of blocks verified by authority 0 ({})",
1070 observer_received_blocks,
1071 authority_0_total_verified_blocks,
1072 );
1073
1074 observer.stop().await;
1076
1077 for authority in authorities {
1079 authority.stop().await;
1080 }
1081 }
1082
1083 #[rstest]
1084 #[tokio::test(flavor = "current_thread")]
1085 async fn test_small_committee(
1086 #[values(NetworkType::Tonic)] network_type: NetworkType,
1087 #[values(1, 2, 3)] num_authorities: usize,
1088 ) {
1089 telemetry_subscribers::init_for_testing();
1090 let db_registry = Registry::new();
1091 DBMetrics::init(RegistryService::new(db_registry));
1092
1093 let (committee, keypairs) = local_committee_and_keys(0, vec![1; num_authorities]);
1094 let protocol_config = ConsensusProtocolConfig::for_testing();
1095
1096 let temp_dirs = (0..num_authorities)
1097 .map(|_| TempDir::new().unwrap())
1098 .collect::<Vec<_>>();
1099
1100 let mut output_receivers = Vec::with_capacity(committee.size());
1101 let mut authorities: Vec<ConsensusAuthority> = Vec::with_capacity(committee.size());
1102 let mut boot_counters = vec![0; num_authorities];
1103
1104 for (index, _authority_info) in committee.authorities() {
1105 let (authority, commit_receiver) = make_authority(
1106 index,
1107 &temp_dirs[index.value()],
1108 committee.clone(),
1109 keypairs.clone(),
1110 network_type,
1111 boot_counters[index],
1112 protocol_config.clone(),
1113 )
1114 .await;
1115 boot_counters[index] += 1;
1116 output_receivers.push(commit_receiver);
1117 authorities.push(authority);
1118 }
1119
1120 const NUM_TRANSACTIONS: u8 = 15;
1121 let mut submitted_transactions = BTreeSet::<Vec<u8>>::new();
1122 for i in 0..NUM_TRANSACTIONS {
1123 let txn = vec![i; 16];
1124 submitted_transactions.insert(txn.clone());
1125 authorities[i as usize % authorities.len()]
1126 .transaction_client()
1127 .submit(vec![txn], Priority::Normal)
1128 .await
1129 .unwrap();
1130 }
1131
1132 for receiver in &mut output_receivers {
1133 let mut expected_transactions = submitted_transactions.clone();
1134 loop {
1135 let committed_subdag =
1136 tokio::time::timeout(Duration::from_secs(1), receiver.recv())
1137 .await
1138 .unwrap()
1139 .unwrap();
1140 for b in committed_subdag.blocks {
1141 for txn in b.transactions().iter().map(|t| t.data().to_vec()) {
1142 assert!(
1143 expected_transactions.remove(&txn),
1144 "Transaction not submitted or already seen: {:?}",
1145 txn
1146 );
1147 }
1148 }
1149 if expected_transactions.is_empty() {
1150 break;
1151 }
1152 }
1153 }
1154
1155 let index = committee.to_authority_index(0).unwrap();
1157 authorities.remove(index.value()).stop().await;
1158 sleep(Duration::from_secs(10)).await;
1159
1160 let (authority, commit_receiver) = make_authority(
1162 index,
1163 &temp_dirs[index.value()],
1164 committee.clone(),
1165 keypairs.clone(),
1166 network_type,
1167 boot_counters[index],
1168 protocol_config.clone(),
1169 )
1170 .await;
1171 boot_counters[index] += 1;
1172 output_receivers[index] = commit_receiver;
1173 authorities.insert(index.value(), authority);
1174 sleep(Duration::from_secs(10)).await;
1175
1176 for authority in authorities {
1178 authority.stop().await;
1179 }
1180 }
1181
1182 #[rstest]
1183 #[tokio::test(flavor = "current_thread")]
1184 async fn test_amnesia_recovery_success(#[values(5, 10)] gc_depth: u32) {
1185 telemetry_subscribers::init_for_testing();
1186 let db_registry = Registry::new();
1187 DBMetrics::init(RegistryService::new(db_registry));
1188
1189 const NUM_OF_AUTHORITIES: usize = 4;
1190 let (committee, keypairs) = local_committee_and_keys(0, [1; NUM_OF_AUTHORITIES].to_vec());
1191 let mut commit_receivers = vec![];
1192 let mut authorities = BTreeMap::new();
1193 let mut temp_dirs = BTreeMap::new();
1194 let mut boot_counters = [0; NUM_OF_AUTHORITIES];
1195
1196 let mut protocol_config = ConsensusProtocolConfig::for_testing();
1197 protocol_config.set_gc_depth_for_testing(gc_depth);
1198
1199 for (index, _authority_info) in committee.authorities() {
1200 let dir = TempDir::new().unwrap();
1201 let (authority, commit_receiver) = make_authority(
1202 index,
1203 &dir,
1204 committee.clone(),
1205 keypairs.clone(),
1206 NetworkType::Tonic,
1207 boot_counters[index],
1208 protocol_config.clone(),
1209 )
1210 .await;
1211 boot_counters[index] += 1;
1212 commit_receivers.push(commit_receiver);
1213 authorities.insert(index, authority);
1214 temp_dirs.insert(index, dir);
1215 }
1216
1217 let index_1 = committee.to_authority_index(1).unwrap();
1221 'outer: while let Some(result) =
1222 timeout(Duration::from_secs(10), commit_receivers[index_1].recv())
1223 .await
1224 .expect("Timed out while waiting for at least one committed block from authority 1")
1225 {
1226 for block in result.blocks {
1227 if block.round() > GENESIS_ROUND && block.author() == index_1 {
1228 break 'outer;
1229 }
1230 }
1231 }
1232
1233 authorities.remove(&index_1).unwrap().stop().await;
1239 let index_2 = committee.to_authority_index(2).unwrap();
1240 authorities.remove(&index_2).unwrap().stop().await;
1241 sleep(Duration::from_secs(5)).await;
1242
1243 let dir = TempDir::new().unwrap();
1247 boot_counters[index_1] = 0;
1249 let (authority, mut commit_receiver) = make_authority(
1250 index_1,
1251 &dir,
1252 committee.clone(),
1253 keypairs.clone(),
1254 NetworkType::Tonic,
1255 boot_counters[index_1],
1256 protocol_config.clone(),
1257 )
1258 .await;
1259 boot_counters[index_1] += 1;
1260 authorities.insert(index_1, authority);
1261 temp_dirs.insert(index_1, dir);
1262 sleep(Duration::from_secs(5)).await;
1263
1264 let (authority, _commit_receiver) = make_authority(
1267 index_2,
1268 &temp_dirs[&index_2],
1269 committee.clone(),
1270 keypairs,
1271 NetworkType::Tonic,
1272 boot_counters[index_2],
1273 protocol_config.clone(),
1274 )
1275 .await;
1276 boot_counters[index_2] += 1;
1277 authorities.insert(index_2, authority);
1278 sleep(Duration::from_secs(5)).await;
1279
1280 'outer: while let Some(result) = commit_receiver.recv().await {
1282 for block in result.blocks {
1283 if block.round() > GENESIS_ROUND && block.author() == index_1 {
1284 break 'outer;
1285 }
1286 }
1287 }
1288
1289 for (_, authority) in authorities {
1291 authority.stop().await;
1292 }
1293 }
1294
1295 async fn make_authority(
1297 index: AuthorityIndex,
1298 db_dir: &TempDir,
1299 committee: Committee,
1300 keypairs: Vec<(NetworkKeyPair, ProtocolKeyPair)>,
1301 network_type: NetworkType,
1302 boot_counter: u64,
1303 protocol_config: ConsensusProtocolConfig,
1304 ) -> (ConsensusAuthority, UnboundedReceiver<CommittedSubDag>) {
1305 make_authority_with_observer_server(
1306 index,
1307 db_dir,
1308 committee,
1309 keypairs,
1310 network_type,
1311 boot_counter,
1312 protocol_config,
1313 None, )
1315 .await
1316 }
1317
1318 async fn make_authority_with_observer_server(
1319 index: AuthorityIndex,
1320 db_dir: &TempDir,
1321 committee: Committee,
1322 keypairs: Vec<(NetworkKeyPair, ProtocolKeyPair)>,
1323 network_type: NetworkType,
1324 boot_counter: u64,
1325 protocol_config: ConsensusProtocolConfig,
1326 observer_server_port: Option<u16>,
1327 ) -> (ConsensusAuthority, UnboundedReceiver<CommittedSubDag>) {
1328 let registry = Registry::new();
1329
1330 let mut parameters = Parameters {
1332 db_path: db_dir.path().to_path_buf(),
1333 dag_state_cached_rounds: 5,
1334 commit_sync_parallel_fetches: 2,
1335 commit_sync_batch_size: 3,
1336 sync_last_known_own_block_timeout: Duration::from_millis(2_000),
1337 ..Default::default()
1338 };
1339
1340 if let Some(port) = observer_server_port {
1342 parameters.observer.server_port = Some(port);
1343 }
1344
1345 let txn_verifier = NoopTransactionVerifier {};
1346
1347 let protocol_keypair = keypairs[index].1.clone();
1348 let network_keypair = keypairs[index].0.clone();
1349
1350 let (commit_consumer, commit_receiver) = CommitConsumerArgs::new(0, 0);
1351
1352 let authority = ConsensusAuthority::start(
1353 network_type,
1354 0,
1355 committee,
1356 parameters,
1357 protocol_config,
1358 Some(protocol_keypair),
1359 network_keypair,
1360 Arc::new(Clock::default()),
1361 Arc::new(txn_verifier),
1362 None,
1363 commit_consumer,
1364 registry,
1365 boot_counter,
1366 None,
1367 )
1368 .await;
1369
1370 (authority, commit_receiver)
1371 }
1372}