Skip to content

Commit 63ed510

Browse files
committed
refactor: remove anti-cheat weight manipulation for pure pass-through
- Remove weight caps (max_weight_fraction: 0.5 -> 1.0) - Disable softmax, use simple linear normalization - Add BURN_UID constant for UID 0 (burn address) - Mark anti_cheat_weights module as LEGACY/DEPRECATED - Challenges now receive pure weights based on emission percentage - Unused weight goes to UID 0
1 parent cb30a93 commit 63ed510

File tree

3 files changed

+42
-67
lines changed

3 files changed

+42
-67
lines changed

crates/challenge-runtime/src/anti_cheat_weights.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
1-
//! Anti-Cheat Weight Calculation
1+
//! Anti-Cheat Weight Calculation (LEGACY/DEPRECATED)
22
//!
3-
//! Calculates weights for agents in a way that prevents validator manipulation:
3+
//! **NOTE: This module is deprecated. Weight manipulation has been removed from the platform.**
44
//!
5+
//! The platform now uses pure pass-through weights:
6+
//! - Challenges receive weights based directly on their emission percentage
7+
//! - No outlier detection, no weight caps, no manipulation
8+
//! - Unused weight is sent to UID 0 (burn address)
9+
//!
10+
//! This module is kept for reference but should not be used in production.
11+
//!
12+
//! Original design (no longer active):
513
//! 1. **Outlier Detection**: Remove scores that deviate significantly from median
614
//! 2. **Consensus Requirement**: Agent must have valid scores from ≥50% of validators
715
//! 3. **Top Position Requirement**: Agent must be #1 on ≥50% of validators (by count, not stake)
816
//! 4. **Stake-Weighted Average**: Final score uses stake weights (after outlier removal)
917
//! 5. **Slashing Detection**: Flag validators whose scores consistently deviate
10-
//!
11-
//! This prevents:
12-
//! - Single high-stake validator from manipulating results
13-
//! - Colluding minority from pushing bad agents
14-
//! - Validators from lying about evaluation results
1518
1619
use serde::{Deserialize, Serialize};
1720
use std::collections::{HashMap, HashSet};

crates/challenge-runtime/src/weight_calculator.rs

Lines changed: 29 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,29 @@
11
//! Weight Calculator
22
//!
33
//! Converts challenge leaderboard scores to Bittensor weights.
4-
//! Handles normalization, edge cases, and commit-reveal protocol.
4+
//! Pure pass-through of challenge weights - no manipulation.
5+
//! Unused weight automatically goes to UID 0 (burn address).
56
67
use serde::{Deserialize, Serialize};
78
use tracing::{info, warn};
89

910
/// Maximum weight value for Bittensor (u16 max)
1011
pub const MAX_WEIGHT: u16 = 65535;
1112

13+
/// UID 0 is the burn address - receives all unused weight
14+
pub const BURN_UID: u16 = 0;
15+
1216
/// Weight calculator configuration
1317
#[derive(Debug, Clone, Serialize, Deserialize)]
1418
pub struct WeightCalculatorConfig {
15-
/// Minimum score to receive any weight
19+
/// Minimum score to receive any weight (default: 0.0 = no threshold)
1620
pub min_score_threshold: f64,
1721
/// Temperature for softmax (higher = more distributed weights)
1822
pub temperature: f64,
1923
/// Whether to use softmax or linear normalization
2024
pub use_softmax: bool,
21-
/// Maximum weight any single UID can receive (as fraction)
25+
/// Maximum weight any single UID can receive (as fraction) - DISABLED (set to 1.0)
26+
/// NOTE: Weight cap removed - challenges receive pure weights based on emission %
2227
pub max_weight_fraction: f64,
2328
/// Mechanism ID for this challenge
2429
pub mechanism_id: u8,
@@ -29,8 +34,8 @@ impl Default for WeightCalculatorConfig {
2934
Self {
3035
min_score_threshold: 0.0,
3136
temperature: 1.0,
32-
use_softmax: true,
33-
max_weight_fraction: 0.5, // No single UID gets > 50%
37+
use_softmax: false, // Use simple linear normalization
38+
max_weight_fraction: 1.0, // No cap - pure weights
3439
mechanism_id: 0,
3540
}
3641
}
@@ -185,52 +190,14 @@ impl WeightCalculator {
185190
.collect()
186191
}
187192

188-
/// Apply max weight cap and redistribute
189-
fn apply_weight_cap(&self, mut weights: Vec<(u16, f64, f64)>) -> Vec<(u16, f64, f64)> {
190-
let max = self.config.max_weight_fraction;
191-
192-
// Sort by weight descending
193-
weights.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
194-
195-
let mut excess = 0.0;
196-
let mut capped_count = 0;
197-
198-
// Cap weights that exceed max
199-
for (_, weight, _) in weights.iter_mut() {
200-
if *weight > max {
201-
excess += *weight - max;
202-
*weight = max;
203-
capped_count += 1;
204-
}
205-
}
206-
207-
if excess > 0.0 && capped_count < weights.len() {
208-
// Redistribute excess to non-capped weights
209-
let uncapped: Vec<usize> = weights
210-
.iter()
211-
.enumerate()
212-
.filter(|(_, (_, w, _))| *w < max)
213-
.map(|(i, _)| i)
214-
.collect();
215-
216-
let extra_per = excess / uncapped.len() as f64;
217-
for i in uncapped {
218-
weights[i].1 += extra_per;
219-
// Re-cap if needed
220-
if weights[i].1 > max {
221-
weights[i].1 = max;
222-
}
223-
}
224-
}
225-
226-
// Normalize to ensure sum = 1.0
227-
let sum: f64 = weights.iter().map(|(_, w, _)| w).sum();
228-
if sum > 0.0 {
229-
for (_, w, _) in weights.iter_mut() {
230-
*w /= sum;
231-
}
232-
}
233-
193+
/// Apply weight cap (DISABLED - pure pass-through)
194+
///
195+
/// NOTE: Weight caps have been removed for simpler, more transparent weight distribution.
196+
/// Challenges receive weights purely based on their emission percentage.
197+
/// Unused weight is sent to UID 0 (burn address).
198+
fn apply_weight_cap(&self, weights: Vec<(u16, f64, f64)>) -> Vec<(u16, f64, f64)> {
199+
// No cap applied - return weights as-is
200+
// Normalization already done in normalize_scores()
234201
weights
235202
}
236203

@@ -385,15 +352,16 @@ mod tests {
385352
}
386353

387354
#[test]
388-
fn test_weight_cap() {
355+
fn test_no_weight_cap() {
356+
// Weight caps are DISABLED - pure pass-through
389357
let config = WeightCalculatorConfig {
390358
use_softmax: false,
391-
max_weight_fraction: 0.5, // 50% max
359+
max_weight_fraction: 1.0, // No cap (default)
392360
..Default::default()
393361
};
394362
let calc = WeightCalculator::new(config);
395363

396-
// One score dominates
364+
// One score dominates - should get proportional weight
397365
let scores = vec![
398366
MinerScore {
399367
uid: 1,
@@ -415,10 +383,13 @@ mod tests {
415383

416384
let result = calc.calculate(&scores, 1);
417385

418-
// Verify cap is applied - no weight should exceed 50%
419-
for w in &result.weights {
420-
assert!(w.normalized <= 0.51, "Weight {} exceeds cap", w.normalized);
421-
}
386+
// With pure pass-through, weights should be proportional to scores
387+
// Score 0.9 / 1.0 = 90% weight, Score 0.1 / 1.0 = 10% weight
388+
let uid1_weight = result.weights.iter().find(|w| w.uid == 1).unwrap();
389+
let uid2_weight = result.weights.iter().find(|w| w.uid == 2).unwrap();
390+
391+
assert!(uid1_weight.normalized > 0.85, "UID 1 should get ~90% weight: {}", uid1_weight.normalized);
392+
assert!(uid2_weight.normalized < 0.15, "UID 2 should get ~10% weight: {}", uid2_weight.normalized);
422393

423394
// Verify weights still sum to 1.0
424395
let sum: f64 = result.weights.iter().map(|w| w.normalized).sum();

crates/core/src/message.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,8 @@ pub struct MechanismWeightConfig {
475475
pub equal_distribution: bool,
476476
/// Minimum weight per miner (prevents dust weights)
477477
pub min_weight_threshold: f64,
478-
/// Maximum weight cap per miner (0.0 = no cap, 0.5 = max 50%)
478+
/// Maximum weight cap per miner (DEPRECATED - set to 1.0)
479+
/// NOTE: Weight caps have been removed. Challenges receive pure weights.
479480
pub max_weight_cap: f64,
480481
/// Whether this mechanism is active
481482
pub active: bool,
@@ -488,7 +489,7 @@ impl MechanismWeightConfig {
488489
base_burn_rate: 0.0,
489490
equal_distribution: true,
490491
min_weight_threshold: 0.0001,
491-
max_weight_cap: 0.5,
492+
max_weight_cap: 1.0, // No cap - pure weights
492493
active: true,
493494
}
494495
}

0 commit comments

Comments
 (0)