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 }