Skip to content

Commit 4d3f0ff

Browse files
author
EchoBT
committed
refactor: event-driven commit/reveal from Bittensor timing
Major changes: - Update bittensor-rs to c54fc3d (always emit phase events) - Remove phase-based commit/reveal triggers from runtime - Add CommitWindowOpen handler that collects and submits weights - RevealWindowOpen triggers pending commit reveals - Add collect_and_get_weights() for event-driven weight collection This makes evaluation truly continuous - commit/reveal only happen when Bittensor timing events fire, not based on internal phases.
1 parent 3291318 commit 4d3f0ff

File tree

4 files changed

+106
-23
lines changed

4 files changed

+106
-23
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ license = "MIT"
3030

3131
[workspace.dependencies]
3232
# Bittensor
33-
bittensor-rs = { git = "https://github.com/CortexLM/bittensor-rs", rev = "c4e6df8ef5005a594a15ec073b9425bc6a6edb09" }
33+
bittensor-rs = { git = "https://github.com/CortexLM/bittensor-rs", rev = "c54fc3d" }
3434

3535
# Async runtime
3636
tokio = { version = "1.40", features = ["full", "sync", "macros", "rt-multi-thread"] }

bins/validator-node/src/main.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,29 @@ async fn main() -> Result<()> {
829829
}
830830
BlockSyncEvent::CommitWindowOpen { epoch, block } => {
831831
info!("Commit window opened for epoch {} at block {}", epoch, block);
832+
833+
// Collect and commit weights for all mechanisms
834+
// This is the primary trigger for weight submission (event-driven from Bittensor)
835+
836+
// Collect weights from all challenges (async)
837+
let mechanism_weights = runtime_for_blocks.collect_and_get_weights().await;
838+
839+
if let Some(ref submitter) = weight_submitter_clone {
840+
let weights_to_submit = if mechanism_weights.is_empty() {
841+
// No challenge weights - submit burn weights to UID 0
842+
info!("No challenge weights for epoch {} - submitting burn weights", epoch);
843+
vec![(0u8, vec![0u16], vec![65535u16])]
844+
} else {
845+
info!("Committing weights for {} mechanisms", mechanism_weights.len());
846+
mechanism_weights
847+
};
848+
849+
let mut sub = submitter.lock().await;
850+
match sub.submit_mechanism_weights_batch(&weights_to_submit).await {
851+
Ok(tx) => info!("Mechanism weights committed to Bittensor: {}", tx),
852+
Err(e) => error!("Failed to commit mechanism weights: {}", e),
853+
}
854+
}
832855
}
833856
BlockSyncEvent::RevealWindowOpen { epoch, block } => {
834857
info!("Reveal window opened for epoch {} at block {}", epoch, block);

crates/challenge-runtime/src/runtime.rs

Lines changed: 81 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -309,26 +309,12 @@ impl ChallengeRuntime {
309309
Ok(())
310310
}
311311

312-
/// Handle phase change
312+
/// Handle phase change - just logs, does not trigger commit/reveal
313+
///
314+
/// Commit/reveal are triggered by Bittensor events (CommitWindowOpen, RevealWindowOpen)
315+
/// not by internal phase tracking. This ensures timing matches Bittensor exactly.
313316
async fn on_phase_change(&self, epoch: u64, phase: EpochPhase) -> Result<(), RuntimeError> {
314-
info!("Epoch {} phase: {}", epoch, phase);
315-
316-
match phase {
317-
EpochPhase::Commit => {
318-
// Calculate and commit weights for all challenges
319-
self.commit_weights(epoch).await?;
320-
}
321-
EpochPhase::Reveal => {
322-
// Reveal weights for all challenges
323-
self.reveal_weights(epoch).await?;
324-
}
325-
EpochPhase::Finalization => {
326-
// Finalize weights
327-
self.finalize_weights(epoch).await?;
328-
}
329-
_ => {}
330-
}
331-
317+
info!("Epoch {} phase: {} (info only - actions triggered by Bittensor events)", epoch, phase);
332318
Ok(())
333319
}
334320

@@ -400,7 +386,9 @@ impl ChallengeRuntime {
400386
}
401387

402388
/// Commit weights for all mechanisms
403-
async fn commit_weights(&self, epoch: u64) -> Result<(), RuntimeError> {
389+
///
390+
/// Called when Bittensor CommitWindowOpen event fires.
391+
pub async fn commit_weights(&self, epoch: u64) -> Result<(), RuntimeError> {
404392
info!("Committing weights for epoch {} (per mechanism)", epoch);
405393

406394
// First collect weights from all challenges
@@ -449,7 +437,9 @@ impl ChallengeRuntime {
449437
}
450438

451439
/// Reveal weights for all mechanisms
452-
async fn reveal_weights(&self, epoch: u64) -> Result<(), RuntimeError> {
440+
///
441+
/// Called when Bittensor RevealWindowOpen event fires.
442+
pub async fn reveal_weights(&self, epoch: u64) -> Result<(), RuntimeError> {
453443
info!("Revealing weights for epoch {} (per mechanism)", epoch);
454444

455445
let all_mechanisms = self.mechanism_weights.read().list_mechanisms();
@@ -524,10 +514,80 @@ impl ChallengeRuntime {
524514

525515
/// Get all mechanism weights for batch submission to Bittensor
526516
/// Returns Vec<(mechanism_id, uids, weights)> for use with batch_set_mechanism_weights
517+
///
518+
/// Note: This returns revealed weights from internal commit-reveal.
519+
/// For direct weights, use collect_and_get_weights() instead.
527520
pub fn get_mechanism_weights_for_submission(&self) -> Vec<(u8, Vec<u16>, Vec<u16>)> {
528521
self.mechanism_commit_reveal.get_revealed_weights()
529522
}
530523

524+
/// Collect weights from all challenges and return them for Bittensor submission
525+
///
526+
/// This is the primary method for event-driven weight submission.
527+
/// Called when Bittensor CommitWindowOpen event fires.
528+
pub async fn collect_and_get_weights(&self) -> Vec<(u8, Vec<u16>, Vec<u16>)> {
529+
let epoch = self.epoch_manager.current_epoch();
530+
info!("Collecting weights for epoch {} (event-driven)", epoch);
531+
532+
let mut result = Vec::new();
533+
534+
for challenge_id in self.manager.list_challenges() {
535+
let mechanism_id = match self.challenge_mechanisms.read().get(&challenge_id) {
536+
Some(id) => *id,
537+
None => {
538+
warn!("Challenge {} has no mechanism_id, skipping", challenge_id);
539+
continue;
540+
}
541+
};
542+
543+
let ctx = match self.manager.get_context(&challenge_id) {
544+
Some(ctx) => ctx,
545+
None => continue,
546+
};
547+
548+
let challenge = match self.manager.get_challenge(&challenge_id) {
549+
Some(c) => c,
550+
None => continue,
551+
};
552+
553+
// Calculate weights from this challenge
554+
match challenge.calculate_weights(&ctx).await {
555+
Ok(weights) => {
556+
if weights.is_empty() {
557+
debug!("Challenge {} has no weights", challenge_id);
558+
continue;
559+
}
560+
561+
info!(
562+
"Challenge {} -> mechanism {}: {} weights",
563+
challenge_id,
564+
mechanism_id,
565+
weights.len()
566+
);
567+
568+
// Convert to Bittensor format (uid, weight as u16)
569+
// For now, use placeholder UIDs - actual UID mapping would come from metagraph
570+
let uids: Vec<u16> = (0..weights.len() as u16).collect();
571+
let weight_values: Vec<u16> = weights
572+
.iter()
573+
.map(|w| (w.weight.clamp(0.0, 1.0) * 65535.0) as u16)
574+
.collect();
575+
576+
result.push((mechanism_id, uids, weight_values));
577+
}
578+
Err(e) => {
579+
error!(
580+
"Failed to calculate weights for challenge {}: {}",
581+
challenge_id, e
582+
);
583+
}
584+
}
585+
}
586+
587+
info!("Collected weights for {} mechanisms", result.len());
588+
result
589+
}
590+
531591
/// Get all registered mechanism IDs (for initial weight submission)
532592
pub fn get_registered_mechanism_ids(&self) -> Vec<u8> {
533593
self.challenge_mechanisms

0 commit comments

Comments
 (0)