/ tests / multi_validator.rs
multi_validator.rs
  1  // Copyright (c) 2025 ALPHA/DELTA Network
  2  
  3  //! Multi-validator consensus tests.
  4  //!
  5  //! Tests BFT consensus behavior with multiple validators:
  6  //! - Block production and agreement
  7  //! - View changes on leader failure
  8  //! - Recovery from network issues
  9  //!
 10  //! These tests verify the consensus mechanism works correctly.
 11  
 12  use adnet_test_utils::{init_test_logging, TestRuntime, TestRuntimeBuilder};
 13  use std::time::Duration;
 14  
 15  /// Test that all validators reach the same block height.
 16  #[tokio::test]
 17  #[ignore = "Requires full node integration - placeholder for Phase 5 completion"]
 18  async fn test_consensus_agreement() {
 19      init_test_logging();
 20  
 21      let mut runtime = TestRuntime::four_validators()
 22          .await
 23          .expect("Failed to create test runtime");
 24  
 25      runtime.start().await.expect("Failed to start runtime");
 26  
 27      // Wait for nodes to sync and produce some blocks
 28      // runtime.wait_for_sync().await.expect("Nodes failed to sync");
 29      // runtime.wait_blocks(5).await.expect("Failed to produce blocks");
 30  
 31      // Verify all validators have the same height
 32      // assert!(runtime.validators_in_consensus().await);
 33  
 34      runtime.shutdown().await.expect("Failed to shutdown runtime");
 35  }
 36  
 37  /// Test consensus continues with one validator down (3f+1 = 4, f=1).
 38  #[tokio::test]
 39  #[ignore = "Requires full node integration - placeholder for Phase 5 completion"]
 40  async fn test_consensus_with_one_failure() {
 41      init_test_logging();
 42  
 43      let mut runtime = TestRuntime::four_validators()
 44          .await
 45          .expect("Failed to create test runtime");
 46  
 47      runtime.start().await.expect("Failed to start runtime");
 48  
 49      // Wait for initial sync
 50      // runtime.wait_for_sync().await.expect("Nodes failed to sync");
 51  
 52      // Stop one validator
 53      runtime.stop_validator(3).await.expect("Failed to stop validator");
 54  
 55      // Consensus should continue with 3 validators (BFT threshold met)
 56      // runtime.wait_blocks(3).await.expect("Failed to produce blocks");
 57  
 58      // Verify remaining validators still in consensus
 59      // let heights: Vec<_> = runtime.validators()[..3]
 60      //     .iter()
 61      //     .map(|h| h.alpha_height())
 62      //     .collect();
 63      // assert!(heights.iter().all(|h| *h == heights[0]));
 64  
 65      runtime.shutdown().await.expect("Failed to shutdown runtime");
 66  }
 67  
 68  /// Test view change on leader failure.
 69  #[tokio::test]
 70  #[ignore = "Requires full node integration - placeholder for Phase 5 completion"]
 71  async fn test_view_change_on_leader_failure() {
 72      init_test_logging();
 73  
 74      let mut runtime = TestRuntime::four_validators()
 75          .await
 76          .expect("Failed to create test runtime");
 77  
 78      runtime.start().await.expect("Failed to start runtime");
 79  
 80      // Wait for initial sync
 81      // runtime.wait_for_sync().await.expect("Nodes failed to sync");
 82  
 83      // Identify and stop the current leader (validator 0 by default)
 84      runtime.stop_validator(0).await.expect("Failed to stop leader");
 85  
 86      // Wait for view change and new blocks
 87      // tokio::time::sleep(Duration::from_secs(5)).await;
 88      // runtime.wait_blocks(2).await.expect("Failed to produce blocks after view change");
 89  
 90      // Verify new leader is producing blocks
 91      // let height_before = runtime.validators()[1].alpha_height().await;
 92      // tokio::time::sleep(Duration::from_secs(2)).await;
 93      // let height_after = runtime.validators()[1].alpha_height().await;
 94      // assert!(height_after > height_before);
 95  
 96      runtime.shutdown().await.expect("Failed to shutdown runtime");
 97  }
 98  
 99  /// Test recovery when failed validator comes back.
100  #[tokio::test]
101  #[ignore = "Requires full node integration - placeholder for Phase 5 completion"]
102  async fn test_validator_recovery() {
103      init_test_logging();
104  
105      let mut runtime = TestRuntime::four_validators()
106          .await
107          .expect("Failed to create test runtime");
108  
109      runtime.start().await.expect("Failed to start runtime");
110  
111      // Wait for initial sync
112      // runtime.wait_for_sync().await.expect("Nodes failed to sync");
113  
114      // Stop a validator
115      runtime.stop_validator(2).await.expect("Failed to stop validator");
116  
117      // Wait for some blocks to be produced without it
118      // runtime.wait_blocks(3).await.expect("Failed to produce blocks");
119  
120      // Bring it back
121      runtime.restart_validator(2).await.expect("Failed to restart validator");
122  
123      // Wait for sync
124      // tokio::time::sleep(Duration::from_secs(5)).await;
125  
126      // Verify recovered validator has caught up
127      // assert!(runtime.validators_in_consensus().await);
128  
129      runtime.shutdown().await.expect("Failed to shutdown runtime");
130  }
131  
132  /// Test that 2 validators cannot reach consensus (below BFT threshold).
133  #[tokio::test]
134  #[ignore = "Requires full node integration - placeholder for Phase 5 completion"]
135  async fn test_consensus_fails_below_threshold() {
136      init_test_logging();
137  
138      let mut runtime = TestRuntime::four_validators()
139          .await
140          .expect("Failed to create test runtime");
141  
142      runtime.start().await.expect("Failed to start runtime");
143  
144      // Wait for initial sync
145      // runtime.wait_for_sync().await.expect("Nodes failed to sync");
146  
147      // Get current height
148      // let height_before = runtime.validators()[0].alpha_height().await;
149  
150      // Stop 2 validators (leaves only 2, below 2f+1 threshold for f=1)
151      runtime.stop_validator(2).await.expect("Failed to stop validator 2");
152      runtime.stop_validator(3).await.expect("Failed to stop validator 3");
153  
154      // Wait and verify no progress
155      // tokio::time::sleep(Duration::from_secs(5)).await;
156      // let height_after = runtime.validators()[0].alpha_height().await;
157  
158      // Should not have made significant progress
159      // assert!(height_after <= height_before + 1);
160  
161      runtime.shutdown().await.expect("Failed to shutdown runtime");
162  }
163  
164  /// Test block synchronization when a validator joins late.
165  #[tokio::test]
166  #[ignore = "Requires full node integration - placeholder for Phase 5 completion"]
167  async fn test_late_join_sync() {
168      init_test_logging();
169  
170      // Start with 3 validators initially
171      let mut runtime = TestRuntimeBuilder::new()
172          .validators(3)
173          .clients(0)
174          .build()
175          .await
176          .expect("Failed to create test runtime");
177  
178      runtime.start().await.expect("Failed to start runtime");
179  
180      // Wait for some blocks to be produced
181      // runtime.wait_for_sync().await.expect("Nodes failed to sync");
182      // runtime.wait_blocks(10).await.expect("Failed to produce blocks");
183  
184      // Get current height
185      // let current_height = runtime.validators()[0].alpha_height().await;
186  
187      // A new validator joining would need to sync these blocks
188      // (This would require dynamic node addition which isn't implemented yet)
189  
190      runtime.shutdown().await.expect("Failed to shutdown runtime");
191  }
192  
193  /// Test consensus with clients observing.
194  #[tokio::test]
195  async fn test_validators_with_client_observers() {
196      init_test_logging();
197  
198      let mut runtime = TestRuntime::with_clients(3, 2)
199          .await
200          .expect("Failed to create test runtime");
201  
202      runtime.start().await.expect("Failed to start runtime");
203  
204      // Verify structure
205      assert_eq!(runtime.validators().len(), 3);
206      assert_eq!(runtime.clients().len(), 2);
207  
208      // Clients should be running but not participating in consensus
209      for client in runtime.clients() {
210          assert!(client.is_running().await);
211      }
212  
213      runtime.shutdown().await.expect("Failed to shutdown runtime");
214  }