Skip to content

Commit cff55d7

Browse files
committed
feat: add periodic validator sync to challenge containers
- Sync validators to all challenge containers every 60 seconds - Ensures total_validators is updated even after container restart - Fixes consensus '(1/0 validators)' issue
1 parent 8f4592d commit cff55d7

File tree

1 file changed

+68
-0
lines changed

1 file changed

+68
-0
lines changed

bins/validator-node/src/main.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1798,6 +1798,9 @@ async fn run_validator() -> Result<()> {
17981798
let subtensor_endpoint = args.subtensor_endpoint.clone();
17991799
let mut last_metagraph_sync = std::time::Instant::now();
18001800
let metagraph_sync_interval = std::time::Duration::from_secs(600); // Sync metagraph every 10 minutes
1801+
let mut last_challenge_validator_sync = std::time::Instant::now();
1802+
let challenge_validator_sync_interval = std::time::Duration::from_secs(60); // Sync validators to challenges every minute
1803+
let endpoints_for_sync = challenge_endpoints.clone();
18011804

18021805
// Fetch mechanism count from Bittensor and submit initial weights
18031806
// This prevents vtrust penalty from not having set weights yet
@@ -2504,6 +2507,71 @@ async fn run_validator() -> Result<()> {
25042507
});
25052508
}
25062509

2510+
// Periodic sync of validators to challenge containers
2511+
if last_challenge_validator_sync.elapsed() >= challenge_validator_sync_interval {
2512+
last_challenge_validator_sync = std::time::Instant::now();
2513+
2514+
// Get current validators from chain state
2515+
let validators: Vec<_> = chain_state
2516+
.read()
2517+
.validators
2518+
.iter()
2519+
.map(|(hotkey, info)| {
2520+
serde_json::json!({
2521+
"hotkey": hotkey.to_hex(),
2522+
"stake": info.stake.0,
2523+
"endpoint": ""
2524+
})
2525+
})
2526+
.collect();
2527+
2528+
if !validators.is_empty() {
2529+
// Get all known challenge endpoints
2530+
let endpoints: Vec<(String, String)> = endpoints_for_sync
2531+
.read()
2532+
.iter()
2533+
.map(|(k, v)| (k.clone(), v.clone()))
2534+
.collect();
2535+
2536+
for (challenge_id, endpoint) in endpoints {
2537+
let validators_clone = validators.clone();
2538+
let challenge_id_clone = challenge_id.clone();
2539+
tokio::spawn(async move {
2540+
let sync_url = format!("{}/p2p/validators", endpoint);
2541+
let client = reqwest::Client::new();
2542+
match client
2543+
.post(&sync_url)
2544+
.json(&serde_json::json!({ "validators": validators_clone }))
2545+
.timeout(std::time::Duration::from_secs(5))
2546+
.send()
2547+
.await
2548+
{
2549+
Ok(resp) if resp.status().is_success() => {
2550+
debug!(
2551+
"Periodic sync: {} validators to challenge '{}'",
2552+
validators_clone.len(),
2553+
challenge_id_clone
2554+
);
2555+
}
2556+
Ok(resp) => {
2557+
debug!(
2558+
"Periodic sync to '{}' failed: {}",
2559+
challenge_id_clone,
2560+
resp.status()
2561+
);
2562+
}
2563+
Err(e) => {
2564+
debug!(
2565+
"Periodic sync to '{}' failed: {}",
2566+
challenge_id_clone, e
2567+
);
2568+
}
2569+
}
2570+
});
2571+
}
2572+
}
2573+
}
2574+
25072575
// Log protection stats periodically
25082576
let prot_stats = protection.stats();
25092577
let connected_validators = protection.connected_validator_count();

0 commit comments

Comments
 (0)