Skip to content

Commit 69e455c

Browse files
wip
1 parent 7c67ab5 commit 69e455c

File tree

13 files changed

+569
-114
lines changed

13 files changed

+569
-114
lines changed

pallets/admin-utils/src/benchmarking.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,14 @@ mod benchmarks {
100100
_(RawOrigin::Root, 1u16/*netuid*/, 100u64/*bonds_moving_average*/)/*sudo_set_bonds_moving_average*/;
101101
}
102102

103+
#[benchmark]
104+
fn sudo_set_bonds_penalty() {
105+
pallet_subtensor::Pallet::<T>::init_new_network(1u16 /*netuid*/, 1u16 /*tempo*/);
106+
107+
#[extrinsic_call]
108+
_(RawOrigin::Root, 1u16/*netuid*/, 100u64/*bonds_penalty*/)/*sudo_set_bonds_penalty*/;
109+
}
110+
103111
#[benchmark]
104112
fn sudo_set_max_allowed_validators() {
105113
pallet_subtensor::Pallet::<T>::init_new_network(1u16 /*netuid*/, 1u16 /*tempo*/);

pallets/admin-utils/src/lib.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,22 @@ pub mod pallet {
306306
Ok(())
307307
}
308308

309+
#[pallet::call_index(59)]
310+
#[pallet::weight((
311+
Weight::from_ref_time(14_000_000)
312+
.saturating_add(T::DbWeight::get().reads(1))
313+
.saturating_add(T::DbWeight::get().writes(1)),
314+
DispatchClass::Operational,
315+
Pays::No
316+
))]
317+
pub fn sudo_set_bonds_penalty(
318+
origin: OriginFor<T>,
319+
netuid: u16,
320+
bonds_penalty: u16,
321+
) -> DispatchResult {
322+
Self::do_sudo_set_bonds_penalty(origin, netuid, bonds_penalty)
323+
}
324+
309325
/// The extrinsic sets the adjustment beta for a subnet.
310326
/// It is only callable by the root account or subnet owner.
311327
/// The extrinsic will call the Subtensor pallet to set the adjustment beta.
@@ -685,6 +701,8 @@ pub mod pallet {
685701
Ok(())
686702
}
687703

704+
/// TODO
705+
688706
/// The extrinsic sets the maximum registrations per block for a subnet.
689707
/// It is only callable by the root account.
690708
/// The extrinsic will call the Subtensor pallet to set the maximum registrations per block.

pallets/admin-utils/src/tests/mock.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ parameter_types! {
8686
pub const InitialImmunityPeriod: u16 = 2;
8787
pub const InitialMaxAllowedUids: u16 = 2;
8888
pub const InitialBondsMovingAverage: u64 = 900_000;
89+
pub const InitialBondsPenalty: u16 = 0;
8990
pub const InitialStakePruningMin: u16 = 0;
9091
pub const InitialFoundationDistribution: u64 = 0;
9192
pub const InitialDefaultDelegateTake: u16 = 11_796; // 18% honest number.
@@ -163,6 +164,7 @@ impl pallet_subtensor::Config for Test {
163164
type InitialMaxRegistrationsPerBlock = InitialMaxRegistrationsPerBlock;
164165
type InitialPruningScore = InitialPruningScore;
165166
type InitialBondsMovingAverage = InitialBondsMovingAverage;
167+
type InitialBondsPenalty = InitialBondsPenalty;
166168
type InitialMaxAllowedValidators = InitialMaxAllowedValidators;
167169
type InitialDefaultDelegateTake = InitialDefaultDelegateTake;
168170
type InitialMinDelegateTake = InitialMinDelegateTake;

pallets/admin-utils/src/tests/mod.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,39 @@ fn test_sudo_set_bonds_moving_average() {
741741
});
742742
}
743743

744+
#[test]
745+
fn test_sudo_set_bonds_penalty() {
746+
new_test_ext().execute_with(|| {
747+
let netuid: u16 = 1;
748+
let to_be_set: u16 = 10;
749+
let init_value: u16 = SubtensorModule::get_bonds_penalty(netuid);
750+
add_network(netuid, 10, 0);
751+
assert_eq!(
752+
SubtensorModule::sudo_set_bonds_penalty(
753+
<<Test as Config>::RuntimeOrigin>::signed(U256::from(0)),
754+
netuid,
755+
to_be_set
756+
),
757+
Err(DispatchError::BadOrigin.into())
758+
);
759+
assert_eq!(
760+
SubtensorModule::sudo_set_bonds_penalty(
761+
<<Test as Config>::RuntimeOrigin>::root(),
762+
netuid + 1,
763+
to_be_set
764+
),
765+
Err(Error::<Test>::NetworkDoesNotExist.into())
766+
);
767+
assert_eq!(SubtensorModule::get_bonds_penalty(netuid), init_value);
768+
assert_ok!(SubtensorModule::sudo_set_bonds_penalty(
769+
<<Test as Config>::RuntimeOrigin>::root(),
770+
netuid,
771+
to_be_set
772+
));
773+
assert_eq!(SubtensorModule::get_bonds_penalty(netuid), to_be_set);
774+
});
775+
}
776+
744777
#[test]
745778
fn test_sudo_set_rao_recycled() {
746779
new_test_ext().execute_with(|| {

pallets/subtensor/src/epoch/math.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,6 +1022,79 @@ pub fn weighted_median_col_sparse(
10221022
median
10231023
}
10241024

1025+
// Element-wise interpolation of two matrices: Result = A + ratio * (B - A).
1026+
// ratio is has intended range [0, 1]
1027+
// ratio=0: Result = A
1028+
// ratio=1: Result = B
1029+
#[allow(dead_code)]
1030+
pub fn interpolate(
1031+
mat1: &Vec<Vec<I32F32>>,
1032+
mat2: &Vec<Vec<I32F32>>,
1033+
ratio: I32F32,
1034+
) -> Vec<Vec<I32F32>> {
1035+
if ratio == I32F32::from_num(0) {
1036+
return mat1.clone();
1037+
}
1038+
if ratio == I32F32::from_num(1) {
1039+
return mat2.clone();
1040+
}
1041+
assert!(mat1.len() == mat2.len());
1042+
if mat1.len() == 0 {
1043+
return vec![vec![]; 1];
1044+
}
1045+
if mat1[0].len() == 0 {
1046+
return vec![vec![]; 1];
1047+
}
1048+
let mut result: Vec<Vec<I32F32>> = vec![vec![I32F32::from_num(0); mat1[0].len()]; mat1.len()];
1049+
for i in 0..mat1.len() {
1050+
assert!(mat1[i].len() == mat2[i].len());
1051+
for j in 0..mat1[i].len() {
1052+
result[i][j] = mat1[i][j] + ratio * (mat2[i][j] - mat1[i][j]);
1053+
}
1054+
}
1055+
result
1056+
}
1057+
1058+
// Element-wise interpolation of two sparse matrices: Result = A + ratio * (B - A).
1059+
// ratio is has intended range [0, 1]
1060+
// ratio=0: Result = A
1061+
// ratio=1: Result = B
1062+
#[allow(dead_code)]
1063+
pub fn interpolate_sparse(
1064+
mat1: &Vec<Vec<(u16, I32F32)>>,
1065+
mat2: &Vec<Vec<(u16, I32F32)>>,
1066+
columns: u16,
1067+
ratio: I32F32,
1068+
) -> Vec<Vec<(u16, I32F32)>> {
1069+
if ratio == I32F32::from_num(0) {
1070+
return mat1.clone();
1071+
}
1072+
if ratio == I32F32::from_num(1) {
1073+
return mat2.clone();
1074+
}
1075+
assert!(mat1.len() == mat2.len());
1076+
let rows = mat1.len();
1077+
let zero: I32F32 = I32F32::from_num(0);
1078+
let mut result: Vec<Vec<(u16, I32F32)>> = vec![vec![]; rows];
1079+
for i in 0..rows {
1080+
let mut row1: Vec<I32F32> = vec![zero; columns as usize];
1081+
for (j, value) in mat1[i].iter() {
1082+
row1[*j as usize] = *value;
1083+
}
1084+
let mut row2: Vec<I32F32> = vec![zero; columns as usize];
1085+
for (j, value) in mat2[i].iter() {
1086+
row2[*j as usize] = *value;
1087+
}
1088+
for j in 0..columns as usize {
1089+
let interp: I32F32 = row1[j] + ratio * (row2[j] - row1[j]);
1090+
if zero < interp {
1091+
result[i].push((j as u16, interp))
1092+
}
1093+
}
1094+
}
1095+
result
1096+
}
1097+
10251098
// Element-wise product of two matrices.
10261099
#[allow(dead_code)]
10271100
pub fn hadamard(mat1: &[Vec<I32F32>], mat2: &[Vec<I32F32>]) -> Vec<Vec<I32F32>> {

pallets/subtensor/src/epoch/run_epoch.rs

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -137,18 +137,22 @@ impl<T: Config> Pallet<T> {
137137
// Compute preranks: r_j = SUM(i) w_ij * s_i
138138
let preranks: Vec<I32F32> = matmul(&weights, &active_stake);
139139

140-
// Clip weights at majority consensus
141-
let kappa: I32F32 = Self::get_float_kappa(netuid); // consensus majority ratio, e.g. 51%.
140+
// Consensus majority ratio, e.g. 51%.
141+
let kappa: I32F32 = Self::get_float_kappa(netuid);
142+
// Calculate consensus as stake-weighted median of weights.
142143
let consensus: Vec<I32F32> = weighted_median_col(&active_stake, &weights, kappa);
143-
inplace_col_clip(&mut weights, &consensus);
144-
let validator_trust: Vec<I32F32> = row_sum(&weights);
144+
// Clip weights at majority consensus.
145+
let mut clipped_weights: Vec<Vec<I32F32>> = weights.clone();
146+
inplace_col_clip(&mut clipped_weights, &consensus);
147+
// Calculate validator trust as sum of clipped weights set by validator.
148+
let validator_trust: Vec<I32F32> = row_sum(&clipped_weights);
145149

146150
// ====================================
147151
// == Ranks, Server Trust, Incentive ==
148152
// ====================================
149153

150154
// Compute ranks: r_j = SUM(i) w_ij * s_i
151-
let mut ranks: Vec<I32F32> = matmul(&weights, &active_stake);
155+
let mut ranks: Vec<I32F32> = matmul(&clipped_weights, &active_stake);
152156

153157
// Compute server trust: ratio of rank after vs. rank before.
154158
let trust: Vec<I32F32> = vecdiv(&ranks, &preranks);
@@ -161,14 +165,22 @@ impl<T: Config> Pallet<T> {
161165
// == Bonds and Dividends ==
162166
// =========================
163167

168+
// Get validator bonds penalty in [0, 1].
169+
let bonds_penalty: I32F32 = Self::get_float_bonds_penalty(netuid);
170+
// Calculate weights for bonds, apply bonds penalty to weights.
171+
// bonds_penalty = 0: weights_for_bonds = weights.clone()
172+
// bonds_penalty = 1: weights_for_bonds = clipped_weights.clone()
173+
let weights_for_bonds: Vec<Vec<I32F32>> =
174+
interpolate(&weights, &clipped_weights, bonds_penalty);
175+
164176
// Access network bonds.
165177
let mut bonds: Vec<Vec<I32F32>> = Self::get_bonds(netuid);
166178
inplace_mask_matrix(&outdated, &mut bonds); // mask outdated bonds
167179
inplace_col_normalize(&mut bonds); // sum_i b_ij = 1
168180
log::trace!("B:\n{:?}\n", &bonds);
169181

170182
// Compute bonds delta column normalized.
171-
let mut bonds_delta: Vec<Vec<I32F32>> = row_hadamard(&weights, &active_stake); // ΔB = W◦S
183+
let mut bonds_delta: Vec<Vec<I32F32>> = row_hadamard(&clipped_weights, &active_stake); // ΔB = W◦S
172184
inplace_col_normalize(&mut bonds_delta); // sum_i b_ij = 1
173185
log::trace!("ΔB:\n{:?}\n", &bonds_delta);
174186
// Compute the Exponential Moving Average (EMA) of bonds.
@@ -474,23 +486,26 @@ impl<T: Config> Pallet<T> {
474486
let preranks: Vec<I32F32> = matmul_sparse(&weights, &active_stake, n);
475487
log::trace!("Ranks (before): {:?}", &preranks);
476488

477-
// Clip weights at majority consensus
478-
let kappa: I32F32 = Self::get_float_kappa(netuid); // consensus majority ratio, e.g. 51%.
489+
// Consensus majority ratio, e.g. 51%.
490+
let kappa: I32F32 = Self::get_float_kappa(netuid);
491+
// Calculate consensus as stake-weighted median of weights.
479492
let consensus: Vec<I32F32> = weighted_median_col_sparse(&active_stake, &weights, n, kappa);
480493
log::trace!("Consensus: {:?}", &consensus);
481494

482-
weights = col_clip_sparse(&weights, &consensus);
483-
log::trace!("Weights: {:?}", &weights);
495+
// Clip weights at majority consensus.
496+
let clipped_weights: Vec<Vec<(u16, I32F32)>> = col_clip_sparse(&weights, &consensus);
497+
log::trace!("Clipped Weights: {:?}", &clipped_weights);
484498

485-
let validator_trust: Vec<I32F32> = row_sum_sparse(&weights);
499+
// Calculate validator trust as sum of clipped weights set by validator.
500+
let validator_trust: Vec<I32F32> = row_sum_sparse(&clipped_weights);
486501
log::trace!("Validator Trust: {:?}", &validator_trust);
487502

488503
// =============================
489504
// == Ranks, Trust, Incentive ==
490505
// =============================
491506

492507
// Compute ranks: r_j = SUM(i) w_ij * s_i.
493-
let mut ranks: Vec<I32F32> = matmul_sparse(&weights, &active_stake, n);
508+
let mut ranks: Vec<I32F32> = matmul_sparse(&clipped_weights, &active_stake, n);
494509
log::trace!("Ranks (after): {:?}", &ranks);
495510

496511
// Compute server trust: ratio of rank after vs. rank before.
@@ -505,6 +520,14 @@ impl<T: Config> Pallet<T> {
505520
// == Bonds and Dividends ==
506521
// =========================
507522

523+
// Get validator bonds penalty in [0, 1].
524+
let bonds_penalty: I32F32 = Self::get_float_bonds_penalty(netuid);
525+
// Calculate weights for bonds, apply bonds penalty to weights.
526+
// bonds_penalty = 0: weights_for_bonds = weights.clone()
527+
// bonds_penalty = 1: weights_for_bonds = clipped_weights.clone()
528+
let weights_for_bonds: Vec<Vec<(u16, I32F32)>> =
529+
interpolate_sparse(&weights, &clipped_weights, n, bonds_penalty);
530+
508531
// Access network bonds.
509532
let mut bonds: Vec<Vec<(u16, I32F32)>> = Self::get_bonds_sparse(netuid);
510533
log::trace!("B: {:?}", &bonds);
@@ -523,7 +546,8 @@ impl<T: Config> Pallet<T> {
523546
log::trace!("B (mask+norm): {:?}", &bonds);
524547

525548
// Compute bonds delta column normalized.
526-
let mut bonds_delta: Vec<Vec<(u16, I32F32)>> = row_hadamard_sparse(&weights, &active_stake); // ΔB = W◦S (outdated W masked)
549+
let mut bonds_delta: Vec<Vec<(u16, I32F32)>> =
550+
row_hadamard_sparse(&weights_for_bonds, &active_stake); // ΔB = W◦S (outdated W masked)
527551
log::trace!("ΔB: {:?}", &bonds_delta);
528552

529553
// Normalize bonds delta.
@@ -713,6 +737,9 @@ impl<T: Config> Pallet<T> {
713737
pub fn get_float_kappa(netuid: u16) -> I32F32 {
714738
I32F32::from_num(Self::get_kappa(netuid)).saturating_div(I32F32::from_num(u16::MAX))
715739
}
740+
pub fn get_float_bonds_penalty(netuid: u16) -> I32F32 {
741+
I32F32::from_num(Self::get_bonds_penalty(netuid)) / I32F32::from_num(u16::MAX)
742+
}
716743

717744
pub fn get_block_at_registration(netuid: u16) -> Vec<u64> {
718745
let n = Self::get_subnetwork_n(netuid);

pallets/subtensor/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,11 @@ pub mod pallet {
568568
pub fn DefaultBondsMovingAverage<T: Config>() -> u64 {
569569
T::InitialBondsMovingAverage::get()
570570
}
571+
/// Default bonds penalty.
572+
#[pallet::type_value]
573+
pub fn DefaultBondsPenalty<T: Config>() -> u16 {
574+
T::InitialBondsPenalty::get()
575+
}
571576
#[pallet::type_value]
572577
/// Default validator prune length.
573578
pub fn DefaultValidatorPruneLen<T: Config>() -> u64 {
@@ -1171,6 +1176,10 @@ pub mod pallet {
11711176
/// --- MAP ( netuid ) --> bonds_moving_average
11721177
pub type BondsMovingAverage<T> =
11731178
StorageMap<_, Identity, u16, u64, ValueQuery, DefaultBondsMovingAverage<T>>;
1179+
#[pallet::storage]
1180+
/// --- MAP ( netuid ) --> bonds_penalty
1181+
pub type BondsPenalty<T> =
1182+
StorageMap<_, Identity, u16, u16, ValueQuery, DefaultBondsPenalty<T>>;
11741183
/// --- MAP ( netuid ) --> weights_set_rate_limit
11751184
#[pallet::storage]
11761185
pub type WeightsSetRateLimit<T> =

pallets/subtensor/src/macros/config.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ mod config {
9393
/// Initial bonds moving average.
9494
#[pallet::constant]
9595
type InitialBondsMovingAverage: Get<u64>;
96+
/// Initial bonds penalty.
97+
#[pallet::constant]
98+
type InitialBondsPenalty: Get<u16>;
9699
/// Initial target registrations per interval.
97100
#[pallet::constant]
98101
type InitialTargetRegistrationsPerInterval: Get<u16>;

0 commit comments

Comments
 (0)