Skip to content

Commit acb0a05

Browse files
committed
feat: migrate ChallengeId from UUID to string name + fix persistence gaps
- ChallengeId now wraps a String instead of uuid::Uuid, enabling human-readable challenge names (e.g. 'bounty-challenge') everywhere - Remove Copy trait from ChallengeId (String is not Copy) - Add persist_trigger channel so spawned WASM compilation threads can request immediate state persistence (fixes routes lost on restart) - Fix WASM cache invalidator not persisting after route registration - Fix P2P upload path resetting emission_weight to 0 (now preserves existing config like local upload and consensus paths) - Persist core state immediately after startup WASM reload - Improve error logging on core state deserialization failure - Update all crates and tests for the new ChallengeId type
1 parent 56d8ddb commit acb0a05

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+657
-581
lines changed

Cargo.lock

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

bins/platform-sudo/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@ base64 = "0.21"
2424
hex = { workspace = true }
2525
sp-core = { workspace = true }
2626
rustyline = "14"
27+
uuid = { workspace = true }

bins/platform-sudo/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ impl SudoCli {
207207

208208
// Send challenge_id as-is (name or UUID). Server resolves names to UUIDs.
209209
let id_str = if challenge_id == "new" {
210-
ChallengeId::new().to_string()
210+
uuid::Uuid::new_v4().to_string()
211211
} else {
212212
challenge_id.to_string()
213213
};

bins/validator-node/src/challenge_storage.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ impl StorageBackend for ChallengeStorageBackend {
137137

138138
let msg = P2PMessage::StorageProposal(StorageProposalMessage {
139139
proposal_id,
140-
challenge_id: ChallengeId(challenge_uuid),
140+
challenge_id: ChallengeId::from_string(challenge_id),
141141
proposer: kp.hotkey(),
142142
key: key.to_vec(),
143143
value: value.to_vec(),
@@ -177,7 +177,7 @@ impl StorageBackend for ChallengeStorageBackend {
177177
if let Some(local_tx) = &self.local_proposal_tx {
178178
let local_proposal = StorageProposal {
179179
proposal_id,
180-
challenge_id: ChallengeId(challenge_uuid),
180+
challenge_id: ChallengeId::from_string(challenge_id),
181181
proposer: kp.hotkey(),
182182
key: key.to_vec(),
183183
value: value.to_vec(),

bins/validator-node/src/main.rs

Lines changed: 86 additions & 46 deletions
Large diffs are not rendered by default.

bins/validator-node/tests/integration_test.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ fn test_storage_proposal_consensus_flow() {
7272

7373
let proposal = StorageProposal {
7474
proposal_id,
75-
challenge_id: ChallengeId::new(),
75+
challenge_id: ChallengeId::new("test-challenge"),
7676
proposer: proposer.hotkey(),
7777
key: b"some-key".to_vec(),
7878
value: b"some-value".to_vec(),
@@ -108,14 +108,15 @@ fn test_storage_proposal_consensus_flow() {
108108

109109
#[test]
110110
fn test_epoch_commit_reveal_with_phases() {
111-
let challenge_id = platform_challenge_sdk::ChallengeId::new();
112-
let mut cr_state = CommitRevealState::new(0, challenge_id);
111+
let challenge_id = platform_challenge_sdk::ChallengeId::new("test-challenge");
112+
let mut cr_state = CommitRevealState::new(0, challenge_id.clone());
113113

114114
let v1 = Keypair::generate();
115115
let v2 = Keypair::generate();
116116

117117
// Helper to create commitment + reveal pair
118-
let make_pair = |kp: &Keypair| {
118+
let challenge_id_clone = challenge_id.clone();
119+
let make_pair = move |kp: &Keypair| {
119120
let weights = vec![
120121
platform_challenge_sdk::WeightAssignment::new("agent1".to_string(), 0.7),
121122
platform_challenge_sdk::WeightAssignment::new("agent2".to_string(), 0.3),
@@ -124,14 +125,14 @@ fn test_epoch_commit_reveal_with_phases() {
124125
let hash = platform_challenge_sdk::weights::create_commitment(&weights, &secret);
125126
let commitment = WeightCommitment {
126127
validator: kp.hotkey(),
127-
challenge_id,
128+
challenge_id: challenge_id_clone.clone(),
128129
epoch: 0,
129130
commitment_hash: hash,
130131
timestamp: chrono::Utc::now(),
131132
};
132133
let reveal = WeightReveal {
133134
validator: kp.hotkey(),
134-
challenge_id,
135+
challenge_id: challenge_id_clone.clone(),
135136
epoch: 0,
136137
weights,
137138
secret,
@@ -307,7 +308,7 @@ async fn test_storage_write_feeds_consensus_state() {
307308

308309
let proposal = StorageProposal {
309310
proposal_id,
310-
challenge_id: ChallengeId::new(),
311+
challenge_id: ChallengeId::new("test-challenge"),
311312
proposer: proposer.hotkey(),
312313
key: key.to_bytes(),
313314
value: value.clone(),

crates/challenge-registry/src/health.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ impl HealthMonitor {
147147
/// Register a challenge for health monitoring
148148
pub fn register(&self, challenge_id: ChallengeId) {
149149
let mut state = self.health_state.write();
150-
state.insert(challenge_id, ChallengeHealth::new(challenge_id));
150+
state.insert(challenge_id.clone(), ChallengeHealth::new(challenge_id));
151151
}
152152

153153
/// Unregister a challenge from health monitoring
@@ -209,7 +209,7 @@ mod tests {
209209

210210
#[test]
211211
fn test_health_status() {
212-
let mut health = ChallengeHealth::new(ChallengeId::new());
212+
let mut health = ChallengeHealth::new(ChallengeId::new("test"));
213213

214214
assert_eq!(health.status, HealthStatus::Unknown);
215215
assert!(!health.is_healthy());
@@ -230,9 +230,9 @@ mod tests {
230230
#[test]
231231
fn test_health_monitor() {
232232
let monitor = HealthMonitor::new();
233-
let id = ChallengeId::new();
233+
let id = ChallengeId::new("test");
234234

235-
monitor.register(id);
235+
monitor.register(id.clone());
236236
assert!(monitor.get_health(&id).is_some());
237237

238238
monitor.record_success(&id, 100.0);
@@ -245,7 +245,7 @@ mod tests {
245245

246246
#[test]
247247
fn test_response_time_averaging() {
248-
let mut health = ChallengeHealth::new(ChallengeId::new());
248+
let mut health = ChallengeHealth::new(ChallengeId::new("test"));
249249

250250
health.record_success(100.0);
251251
assert_eq!(health.avg_response_time_ms, 100.0);
@@ -263,8 +263,8 @@ mod tests {
263263

264264
#[test]
265265
fn test_challenge_health_new() {
266-
let challenge_id = ChallengeId::new();
267-
let health = ChallengeHealth::new(challenge_id);
266+
let challenge_id = ChallengeId::new("test");
267+
let health = ChallengeHealth::new(challenge_id.clone());
268268

269269
assert_eq!(health.challenge_id, challenge_id);
270270
assert_eq!(health.status, HealthStatus::Unknown);
@@ -276,7 +276,7 @@ mod tests {
276276

277277
#[test]
278278
fn test_challenge_health_metrics() {
279-
let mut health = ChallengeHealth::new(ChallengeId::new());
279+
let mut health = ChallengeHealth::new(ChallengeId::new("test"));
280280

281281
health.metrics.insert("cpu_usage".to_string(), 45.5);
282282
health.metrics.insert("memory_mb".to_string(), 512.0);
@@ -337,20 +337,20 @@ mod tests {
337337
#[test]
338338
fn test_health_monitor_get_all_health() {
339339
let monitor = HealthMonitor::new();
340-
let id1 = ChallengeId::new();
341-
let id2 = ChallengeId::new();
342-
let id3 = ChallengeId::new();
340+
let id1 = ChallengeId::new("test1");
341+
let id2 = ChallengeId::new("test2");
342+
let id3 = ChallengeId::new("test3");
343343

344344
assert!(monitor.get_all_health().is_empty());
345345

346-
monitor.register(id1);
347-
monitor.register(id2);
348-
monitor.register(id3);
346+
monitor.register(id1.clone());
347+
monitor.register(id2.clone());
348+
monitor.register(id3.clone());
349349

350350
let all_health = monitor.get_all_health();
351351
assert_eq!(all_health.len(), 3);
352352

353-
let ids: Vec<ChallengeId> = all_health.iter().map(|h| h.challenge_id).collect();
353+
let ids: Vec<ChallengeId> = all_health.iter().map(|h| h.challenge_id.clone()).collect();
354354
assert!(ids.contains(&id1));
355355
assert!(ids.contains(&id2));
356356
assert!(ids.contains(&id3));
@@ -359,9 +359,9 @@ mod tests {
359359
#[test]
360360
fn test_health_monitor_update_health() {
361361
let monitor = HealthMonitor::new();
362-
let id = ChallengeId::new();
362+
let id = ChallengeId::new("test");
363363

364-
monitor.register(id);
364+
monitor.register(id.clone());
365365
let health = monitor.get_health(&id).expect("should be registered");
366366
assert_eq!(health.status, HealthStatus::Unknown);
367367

@@ -413,7 +413,7 @@ mod tests {
413413

414414
#[test]
415415
fn test_challenge_health_consecutive_successes() {
416-
let mut health = ChallengeHealth::new(ChallengeId::new());
416+
let mut health = ChallengeHealth::new(ChallengeId::new("test"));
417417

418418
health.record_failure("error 1".to_string());
419419
health.record_failure("error 2".to_string());

crates/challenge-registry/src/lifecycle.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -274,10 +274,10 @@ mod tests {
274274

275275
#[test]
276276
fn test_lifecycle_event_variants() {
277-
let challenge_id = ChallengeId::new();
277+
let challenge_id = ChallengeId::new("test");
278278

279279
// Test Registered event
280-
let registered_event = LifecycleEvent::Registered { challenge_id };
280+
let registered_event = LifecycleEvent::Registered { challenge_id: challenge_id.clone() };
281281
match registered_event {
282282
LifecycleEvent::Registered { challenge_id: id } => {
283283
assert_eq!(id, challenge_id);
@@ -286,7 +286,7 @@ mod tests {
286286
}
287287

288288
// Test Unregistered event
289-
let unregistered_event = LifecycleEvent::Unregistered { challenge_id };
289+
let unregistered_event = LifecycleEvent::Unregistered { challenge_id: challenge_id.clone() };
290290
match unregistered_event {
291291
LifecycleEvent::Unregistered { challenge_id: id } => {
292292
assert_eq!(id, challenge_id);
@@ -296,7 +296,7 @@ mod tests {
296296

297297
// Test StateChanged event
298298
let state_changed_event = LifecycleEvent::StateChanged {
299-
challenge_id,
299+
challenge_id: challenge_id.clone(),
300300
old_state: LifecycleState::Registered,
301301
new_state: LifecycleState::Starting,
302302
};
@@ -317,7 +317,7 @@ mod tests {
317317
let old_version = ChallengeVersion::new(1, 0, 0);
318318
let new_version = ChallengeVersion::new(1, 1, 0);
319319
let version_changed_event = LifecycleEvent::VersionChanged {
320-
challenge_id,
320+
challenge_id: challenge_id.clone(),
321321
old_version: old_version.clone(),
322322
new_version: new_version.clone(),
323323
};
@@ -336,7 +336,7 @@ mod tests {
336336

337337
// Test Restarted event
338338
let restarted_event = LifecycleEvent::Restarted {
339-
challenge_id,
339+
challenge_id: challenge_id.clone(),
340340
previous_restart_id: Some("old".to_string()),
341341
new_restart_id: Some("new".to_string()),
342342
previous_config_version: 1,

crates/challenge-registry/src/migration.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ impl ChallengeMigration {
319319

320320
/// Start executing a migration plan
321321
pub fn start_migration(&self, plan: MigrationPlan) -> RegistryResult<()> {
322-
let challenge_id = plan.challenge_id;
322+
let challenge_id = plan.challenge_id.clone();
323323

324324
let mut plans = self.active_plans.write();
325325
if plans.contains_key(&challenge_id) {
@@ -433,7 +433,7 @@ mod tests {
433433
#[test]
434434
fn test_migration_plan_creation() {
435435
let migration = ChallengeMigration::new();
436-
let id = ChallengeId::new();
436+
let id = ChallengeId::new("test");
437437

438438
let plan = migration
439439
.create_plan(
@@ -452,11 +452,11 @@ mod tests {
452452
#[test]
453453
fn test_migration_execution() {
454454
let migration = ChallengeMigration::new();
455-
let id = ChallengeId::new();
455+
let id = ChallengeId::new("test");
456456

457457
let plan = migration
458458
.create_plan(
459-
id,
459+
id.clone(),
460460
"test".to_string(),
461461
ChallengeVersion::new(1, 0, 0),
462462
ChallengeVersion::new(1, 0, 1),
@@ -482,7 +482,7 @@ mod tests {
482482
#[test]
483483
fn test_duplicate_migration_prevention() {
484484
let migration = ChallengeMigration::new();
485-
let id = ChallengeId::new();
485+
let id = ChallengeId::new("test");
486486

487487
let plan = migration
488488
.create_plan(
@@ -501,7 +501,7 @@ mod tests {
501501
#[test]
502502
fn test_major_version_migration() {
503503
let migration = ChallengeMigration::new();
504-
let id = ChallengeId::new();
504+
let id = ChallengeId::new("test");
505505

506506
let plan = migration
507507
.create_plan(

crates/challenge-registry/src/registry.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ impl ChallengeEntry {
103103
pub fn new(name: String, version: ChallengeVersion) -> Self {
104104
let now = chrono::Utc::now().timestamp_millis();
105105
Self {
106-
id: ChallengeId::new(),
106+
id: ChallengeId::new(&name),
107107
name,
108108
version,
109109
endpoint: None,
@@ -191,17 +191,17 @@ impl ChallengeRegistry {
191191
));
192192
}
193193

194-
let id = entry.id;
194+
let id = entry.id.clone();
195195
let name = entry.name.clone();
196196

197-
let state_store = Arc::new(StateStore::new(id));
197+
let state_store = Arc::new(StateStore::new(id.clone()));
198198
let registered = RegisteredChallenge { entry, state_store };
199199

200-
challenges.insert(id, registered);
201-
name_index.insert(name.clone(), id);
200+
challenges.insert(id.clone(), registered);
201+
name_index.insert(name.clone(), id.clone());
202202

203203
info!(challenge_id = %id, name = %name, "Challenge registered");
204-
self.emit_event(LifecycleEvent::Registered { challenge_id: id });
204+
self.emit_event(LifecycleEvent::Registered { challenge_id: id.clone() });
205205

206206
Ok(id)
207207
}
@@ -248,7 +248,7 @@ impl ChallengeRegistry {
248248
name_index.remove(&registered.entry.name);
249249

250250
info!(challenge_id = %id, "Challenge unregistered");
251-
self.emit_event(LifecycleEvent::Unregistered { challenge_id: *id });
251+
self.emit_event(LifecycleEvent::Unregistered { challenge_id: id.clone() });
252252

253253
Ok(registered.entry)
254254
}
@@ -306,7 +306,7 @@ impl ChallengeRegistry {
306306
);
307307

308308
self.emit_event(LifecycleEvent::StateChanged {
309-
challenge_id: *id,
309+
challenge_id: id.clone(),
310310
old_state,
311311
new_state,
312312
});
@@ -360,7 +360,7 @@ impl ChallengeRegistry {
360360
);
361361

362362
self.emit_event(LifecycleEvent::VersionChanged {
363-
challenge_id: *id,
363+
challenge_id: id.clone(),
364364
old_version: old_version.clone(),
365365
new_version,
366366
});
@@ -409,7 +409,7 @@ impl ChallengeRegistry {
409409
"Challenge restart configuration updated"
410410
);
411411
self.emit_event(LifecycleEvent::Restarted {
412-
challenge_id: *id,
412+
challenge_id: id.clone(),
413413
previous_restart_id: previous_restart_id.clone(),
414414
new_restart_id: restart_id,
415415
previous_config_version,

0 commit comments

Comments
 (0)