Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions pallets/admin-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2043,6 +2043,33 @@ pub mod pallet {
);
Ok(())
}

/// Sets the validator cut for a subnet.
/// Only callable by subnet owner or root.
#[pallet::call_index(81)]
#[pallet::weight(Weight::from_parts(15_000_000, 0)
.saturating_add(<T as frame_system::Config>::DbWeight::get().reads(1_u64))
.saturating_add(<T as frame_system::Config>::DbWeight::get().writes(1_u64)))]
pub fn sudo_set_validator_cut(
origin: OriginFor<T>,
netuid: NetUid,
cut: u64,
) -> DispatchResult {
let maybe_owner = pallet_subtensor::Pallet::<T>::ensure_sn_owner_or_root_with_limits(
origin.clone(),
netuid,
&[TransactionType::SetValidatorCut],
)?;

pallet_subtensor::Pallet::<T>::set_validator_cut(netuid, cut);
log::debug!("ValidatorCutSet( netuid: {netuid:?}, cut: {cut:?} ) ");
pallet_subtensor::Pallet::<T>::record_owner_rl(
maybe_owner,
netuid,
&[TransactionType::SetValidatorCut],
);
Ok(())
}
}
}

Expand Down
118 changes: 118 additions & 0 deletions pallets/admin-utils/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2895,3 +2895,121 @@ fn test_sudo_set_min_allowed_uids() {
);
});
}

#[test]
fn test_get_validator_cut() {
new_test_ext().execute_with(|| {
let netuid = NetUid::from(1);
let expected_cut: u64 = 5000; // 50% cut

// Set up a network
add_network(netuid, 10);

// Set a validator cut value
SubtensorModule::set_validator_cut(netuid, expected_cut);

// Test that we can retrieve the value
let retrieved_cut = SubtensorModule::get_validator_cut(netuid);
assert_eq!(retrieved_cut, expected_cut);
});
}

#[test]
fn test_set_validator_cut() {
new_test_ext().execute_with(|| {
let netuid = NetUid::from(2);
let initial_cut: u64 = pallet_subtensor::DefaultValidatorCut::<Test>::get();
let new_cut: u64 = 7500; // 75% cut

// Set up a network
add_network(netuid, 10);

// Verify initial value
assert_eq!(SubtensorModule::get_validator_cut(netuid), initial_cut);

// Set new validator cut
SubtensorModule::set_validator_cut(netuid, new_cut);

// Verify the value was set correctly
assert_eq!(SubtensorModule::get_validator_cut(netuid), new_cut);
});
}

#[test]
fn test_sudo_set_validator_cut() {
new_test_ext().execute_with(|| {
let netuid = NetUid::from(3);
let to_be_set: u64 = 4200; // 42% cut

// Set up a network
add_network(netuid, 10);

let sn_owner = U256::from(1324);
// Set the Subnet Owner
SubnetOwner::<Test>::insert(netuid, sn_owner);

let init_value = SubtensorModule::get_validator_cut(netuid);

// Test that non-authorized origin fails (using a regular signed origin)
assert_eq!(
AdminUtils::sudo_set_validator_cut(
<<Test as Config>::RuntimeOrigin>::signed(U256::from(1)),
netuid,
to_be_set
),
Err(DispatchError::BadOrigin)
);
// Value should remain unchangeds
assert_eq!(SubtensorModule::get_validator_cut(netuid), init_value);

assert_ok!(AdminUtils::sudo_set_validator_cut(
<<Test as Config>::RuntimeOrigin>::signed(sn_owner),
netuid,
to_be_set
));

// Verify the value was set correctly
assert_eq!(SubtensorModule::get_validator_cut(netuid), to_be_set);
});
}

#[test]
fn test_sudo_set_validator_cut_root() {
new_test_ext().execute_with(|| {
let netuid = NetUid::from(4);
let to_be_set: u64 = 10000; // 100% cut

// Set up a network
add_network(netuid, 10);

// Test that root can set the validator cut successfully
assert_ok!(AdminUtils::sudo_set_validator_cut(
<<Test as Config>::RuntimeOrigin>::root(),
netuid,
to_be_set
));

// Verify the value was set correctly
assert_eq!(SubtensorModule::get_validator_cut(netuid), to_be_set);
});
}

#[test]
fn test_validator_cut_bounds() {
new_test_ext().execute_with(|| {
let netuid = NetUid::from(5);
let min_cut: u64 = 0; // 0% cut
let max_cut: u64 = u64::MAX; // 100% cut

// Set up a network
add_network(netuid, 10);

// Test minimum value
SubtensorModule::set_validator_cut(netuid, min_cut);
assert_eq!(SubtensorModule::get_validator_cut(netuid), min_cut);

// Test maximum value
SubtensorModule::set_validator_cut(netuid, max_cut);
assert_eq!(SubtensorModule::get_validator_cut(netuid), max_cut);
});
}
14 changes: 10 additions & 4 deletions pallets/subtensor/src/coinbase/run_coinbase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -674,11 +674,17 @@ impl<T: Config> Pallet<T> {
});
log::debug!("incentive_sum: {incentive_sum:?}");

let validator_cut = Self::get_validator_cut(netuid);
log::debug!("validator_cut: {validator_cut:?}");

let pending_validator_alpha = if !incentive_sum.is_zero() {
pending_alpha
.saturating_add(pending_swapped)
.saturating_div(2.into())
.saturating_sub(pending_swapped)
let pending_alpha_f = U96F32::from(pending_alpha.to_u64());
let rate = U96F32::from(validator_cut).saturating_div(u64::MAX.into());
let result = pending_alpha_f
.saturating_add(U96F32::from(pending_swapped.to_u64()))
.saturating_mul(rate)
.saturating_sub(U96F32::from(pending_swapped.to_u64()));
result.saturating_to_num::<u64>().into()
} else {
// If the incentive is 0, then Validators get 100% of the alpha.
pending_alpha
Expand Down
11 changes: 11 additions & 0 deletions pallets/subtensor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1549,6 +1549,17 @@ pub mod pallet {
pub type ImmuneOwnerUidsLimit<T> =
StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultImmuneOwnerUidsLimit<T>>;

#[pallet::type_value]
/// Default validator cut 50%
pub fn DefaultValidatorCut<T: Config>() -> u64 {
u64::MAX / 2
}

#[pallet::storage]
/// --- MAP ( netuid ) --> Validator cut
pub type ValidatorCut<T> =
StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultValidatorCut<T>>;

/// =======================================
/// ==== Subnetwork Consensus Storage ====
/// =======================================
Expand Down
20 changes: 20 additions & 0 deletions pallets/subtensor/src/staking/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,26 @@ impl<T: Config> Pallet<T> {
});
}

/// Gets the validator cut for a given subnet.
///
/// # Arguments
/// * `netuid` - The network UID.
///
/// # Returns
/// The validator cut value for the subnet.
pub fn get_validator_cut(netuid: NetUid) -> u64 {
ValidatorCut::<T>::get(netuid)
}

/// Sets the validator cut for a given subnet.
///
/// # Arguments
/// * `netuid` - The network UID.
/// * `cut` - The validator cut value to set.
pub fn set_validator_cut(netuid: NetUid, cut: u64) {
ValidatorCut::<T>::insert(netuid, cut);
}

pub fn burn_subnet_alpha(_netuid: NetUid, _amount: AlphaCurrency) {
// Do nothing; TODO: record burned alpha in a tracker
}
Expand Down
3 changes: 3 additions & 0 deletions pallets/subtensor/src/utils/rate_limiting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub enum TransactionType {
MechanismCountUpdate,
MechanismEmission,
MaxUidsTrimming,
SetValidatorCut,
}

impl TransactionType {
Expand Down Expand Up @@ -141,6 +142,7 @@ impl From<TransactionType> for u16 {
TransactionType::MechanismCountUpdate => 7,
TransactionType::MechanismEmission => 8,
TransactionType::MaxUidsTrimming => 9,
TransactionType::SetValidatorCut => 10,
}
}
}
Expand All @@ -158,6 +160,7 @@ impl From<u16> for TransactionType {
7 => TransactionType::MechanismCountUpdate,
8 => TransactionType::MechanismEmission,
9 => TransactionType::MaxUidsTrimming,
10 => TransactionType::SetValidatorCut,
_ => TransactionType::Unknown,
}
}
Expand Down
Loading