use blvm_node::node::sync::{SyncCoordinator, SyncState, SyncStateMachine};
use blvm_node::{BlockHeader, Hash};
use blvm_protocol::test_utils::create_test_header;
use blvm_protocol::{BitcoinProtocolEngine, ProtocolVersion};
use std::sync::Arc;
use std::time::Duration;
use tokio::time::timeout;
fn header_at_height(height: u64) -> BlockHeader {
let mut prev_hash = [0u8; 32];
prev_hash[0] = (height % 256) as u8;
create_test_header(1231006505 + height, prev_hash)
}
#[tokio::test]
async fn test_sync_state_rapid_transitions() {
let mut machine = SyncStateMachine::new();
for _ in 0..10 {
machine.transition_to(SyncState::Headers);
machine.transition_to(SyncState::Blocks);
machine.transition_to(SyncState::Synced);
machine.transition_to(SyncState::Initial);
}
assert!(matches!(
machine.state(),
&SyncState::Initial | &SyncState::Headers | &SyncState::Blocks | &SyncState::Synced
));
}
#[tokio::test]
async fn test_sync_state_concurrent_transitions() {
let machine = Arc::new(tokio::sync::Mutex::new(SyncStateMachine::new()));
let mut handles = vec![];
for i in 0..5 {
let machine_clone = Arc::clone(&machine);
handles.push(tokio::spawn(async move {
let mut machine = machine_clone.lock().await;
match i % 4 {
0 => machine.transition_to(SyncState::Headers),
1 => machine.transition_to(SyncState::Blocks),
2 => machine.transition_to(SyncState::Synced),
_ => machine.transition_to(SyncState::Initial),
}
}));
}
futures::future::join_all(handles).await;
let machine = machine.lock().await;
assert!(matches!(
machine.state(),
&SyncState::Initial | &SyncState::Headers | &SyncState::Blocks | &SyncState::Synced
));
}
#[tokio::test]
async fn test_sync_coordinator_peer_disconnection_during_sync() {
let mut coordinator = SyncCoordinator::new();
coordinator.start_sync().unwrap();
assert!(coordinator.progress() >= 0.0 && coordinator.progress() <= 1.0);
}
#[tokio::test]
async fn test_sync_coordinator_chain_tip_divergence() {
let mut coordinator = SyncCoordinator::new();
coordinator.start_sync().unwrap();
assert!(coordinator.progress() >= 0.0 && coordinator.progress() <= 1.0);
}
#[tokio::test]
async fn test_sync_state_machine_error_recovery() {
let mut machine = SyncStateMachine::new();
machine.set_error("Test error".to_string());
assert!(matches!(machine.state(), &SyncState::Error(_)));
machine.transition_to(SyncState::Initial);
assert!(matches!(machine.state(), &SyncState::Initial));
machine.transition_to(SyncState::Headers);
assert!(matches!(machine.state(), &SyncState::Headers));
}
#[tokio::test]
async fn test_sync_state_machine_progress_tracking() {
let mut machine = SyncStateMachine::new();
assert_eq!(machine.progress(), 0.0);
machine.transition_to(SyncState::Headers);
let progress_headers = machine.progress();
machine.transition_to(SyncState::Blocks);
let progress_blocks = machine.progress();
machine.transition_to(SyncState::Synced);
let progress_synced = machine.progress();
assert!(progress_synced >= progress_headers);
assert!(progress_synced >= progress_blocks);
assert!(progress_synced <= 1.0);
}
#[tokio::test]
async fn test_sync_coordinator_concurrent_operations() {
let coordinator = Arc::new(tokio::sync::Mutex::new(SyncCoordinator::new()));
let mut handles = vec![];
for _ in 0..5 {
let coordinator_clone = Arc::clone(&coordinator);
handles.push(tokio::spawn(async move {
let mut coordinator = coordinator_clone.lock().await;
coordinator.start_sync().ok()
}));
}
futures::future::join_all(handles).await;
let coordinator = coordinator.lock().await;
assert!(coordinator.progress() >= 0.0 && coordinator.progress() <= 1.0);
}