Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
18 changes: 13 additions & 5 deletions .github/workflows/check-bittensor-e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -448,11 +448,19 @@ jobs:
path: rust-e2e

- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
env:
GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
for i in 1 2 3; do
if printf '%s' "$GHCR_TOKEN" \
| docker login ghcr.io --username "$GITHUB_ACTOR" --password-stdin; then
exit 0
fi
echo "GHCR login failed (attempt $i), retrying in $((i * 15))s..."
sleep $((i * 15))
done
printf '%s' "$GHCR_TOKEN" \
| docker login ghcr.io --username "$GITHUB_ACTOR" --password-stdin

- name: Pull Docker Image
# GHCR intermittently returns permission_denied/timeouts under the
Expand Down
14 changes: 14 additions & 0 deletions pallets/admin-utils/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,20 @@ mod benchmarks {
_(RawOrigin::Root, netuid, 2000u16, 3000u16);
}

#[benchmark]
fn sudo_set_liquid_alpha_consensus_mode() {
let netuid = NetUid::from(1);
pallet_subtensor::Pallet::<T>::set_admin_freeze_window(0);
pallet_subtensor::Pallet::<T>::init_new_network(netuid, 1u16);

#[extrinsic_call]
_(
RawOrigin::Root,
netuid,
pallet_subtensor::ConsensusMode::Previous,
);
}

#[benchmark]
fn sudo_set_coldkey_swap_announcement_delay() {
#[extrinsic_call]
Expand Down
27 changes: 25 additions & 2 deletions pallets/admin-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub mod pallet {
use frame_system::pallet_prelude::*;
use pallet_evm_chain_id::{self, ChainId};
use pallet_subtensor::{
DefaultMaxAllowedUids,
ConsensusMode, DefaultMaxAllowedUids, MAX_BONDS_MOVING_AVERAGE,
utils::rate_limiting::{Hyperparameter, TransactionType},
};
use sp_runtime::{BoundedVec, PerU16};
Expand Down Expand Up @@ -921,7 +921,7 @@ pub mod pallet {
pallet_subtensor::Pallet::<T>::ensure_admin_window_open(netuid)?;
if maybe_owner.is_some() {
ensure!(
bonds_moving_average <= 975000,
bonds_moving_average <= MAX_BONDS_MOVING_AVERAGE,
Error::<T>::BondsMovingAverageMaxReached
)
}
Expand Down Expand Up @@ -1340,6 +1340,29 @@ pub mod pallet {
res
}

/// Sets which consensus values liquid alpha uses for a subnet.
#[pallet::call_index(104)]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] Use the benchmarked weight for the new extrinsic

The benchmark definition was added, but WeightInfo and both generated implementations still lack sudo_set_liquid_alpha_consensus_mode(). Reusing sudo_set_alpha_values() assigns a profile for different storage accesses and leaves this extrinsic without a generated weight. Run the benchmark action, propagate its output into weights.rs, and reference the new weight function here.

#[pallet::weight(<T as pallet::Config>::WeightInfo::sudo_set_alpha_values())]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] Use the benchmarked weight for the new extrinsic

This new extrinsic is charged as sudo_set_alpha_values, whose generated weight models different storage accesses (LiquidAlphaOn and AlphaValues). The added benchmark is not connected to WeightInfo, so the runtime has no generated weight accounting for LiquidAlphaConsensusMode and its rate-limit writes. Generate the benchmark weights, add sudo_set_liquid_alpha_consensus_mode() to both WeightInfo implementations, and reference it here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] Use the benchmarked weight for the new extrinsic

The benchmark function now exists, but generated WeightInfo still has no sudo_set_liquid_alpha_consensus_mode entry, and this call continues to reuse sudo_set_alpha_values. Generate and commit the admin-utils weights, then reference the new weight function here so the declared reads, writes, proof size, and execution time match this call.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] Use the benchmarked weight for the new extrinsic

The benchmark definition now exists, but WeightInfo and its generated implementations still lack sudo_set_liquid_alpha_consensus_mode(). Reusing sudo_set_alpha_values() assigns measurements for different storage access. Regenerate and commit the admin-utils weights, then reference the new method here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] Use the benchmarked weight for the new extrinsic

The benchmark now exists, but this extrinsic still charges sudo_set_alpha_values(). Its authorization, rate-limit recording, and storage accesses differ, so that weight does not account for the actual reads and writes. Generate the weights and add/use a dedicated sudo_set_liquid_alpha_consensus_mode() method before merge.

pub fn sudo_set_liquid_alpha_consensus_mode(
origin: OriginFor<T>,
netuid: NetUid,
mode: ConsensusMode,
) -> DispatchResult {
let maybe_owner = pallet_subtensor::Pallet::<T>::ensure_sn_owner_or_root_with_limits(
origin,
netuid,
&[Hyperparameter::LiquidAlphaConsensusMode.into()],
)?;
pallet_subtensor::Pallet::<T>::ensure_admin_window_open(netuid)?;
pallet_subtensor::Pallet::<T>::set_liquid_alpha_consensus_mode(netuid, mode);
pallet_subtensor::Pallet::<T>::record_owner_rl(
maybe_owner,
netuid,
&[Hyperparameter::LiquidAlphaConsensusMode.into()],
);
Ok(())
}

/// Sets the duration of the dissolve network schedule.
///
/// This extrinsic allows the root account to set the duration for the dissolve network schedule.
Expand Down
80 changes: 76 additions & 4 deletions pallets/admin-utils/src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{Error, pallet::PrecompileEnable};
use codec::Encode;
use frame_support::{
assert_err, assert_noop, assert_ok,
dispatch::{DispatchClass, GetDispatchInfo, Pays},
Expand Down Expand Up @@ -1348,6 +1349,77 @@ fn test_sudo_set_liquid_alpha_enabled() {
});
}

#[test]
fn test_sudo_set_liquid_alpha_consensus_mode() {
new_test_ext().execute_with(|| {
let netuid = NetUid::from(1);
NetworksAdded::<Test>::insert(netuid, true);
assert_eq!(
SubtensorModule::get_liquid_alpha_consensus_mode(netuid),
ConsensusMode::Auto
);

assert_err!(
AdminUtils::sudo_set_liquid_alpha_consensus_mode(
<<Test as Config>::RuntimeOrigin>::signed(U256::from(1)),
netuid,
ConsensusMode::Previous,
),
DispatchError::BadOrigin
);

for mode in [
ConsensusMode::Current,
ConsensusMode::Previous,
ConsensusMode::Auto,
] {
assert_ok!(AdminUtils::sudo_set_liquid_alpha_consensus_mode(
<<Test as Config>::RuntimeOrigin>::root(),
netuid,
mode,
));
assert_eq!(
SubtensorModule::get_liquid_alpha_consensus_mode(netuid),
mode
);
frame_system::Pallet::<Test>::assert_last_event(RuntimeEvent::SubtensorModule(
Event::LiquidAlphaConsensusModeSet(netuid, mode),
));
}
});
}

#[test]
fn test_subnet_owner_can_set_liquid_alpha_consensus_mode() {
new_test_ext().execute_with(|| {
let netuid = NetUid::from(1);
let owner = U256::from(10);
add_network(netuid, 10);
SubnetOwner::<Test>::insert(netuid, owner);
SubtensorModule::set_admin_freeze_window(0);

assert_ok!(AdminUtils::sudo_set_liquid_alpha_consensus_mode(
<<Test as Config>::RuntimeOrigin>::signed(owner),
netuid,
ConsensusMode::Previous,
));
assert_eq!(
SubtensorModule::get_liquid_alpha_consensus_mode(netuid),
ConsensusMode::Previous
);
});
}

#[test]
fn regression_liquid_alpha_consensus_mode_call_index() {
let call = crate::Call::<Test>::sudo_set_liquid_alpha_consensus_mode {
netuid: NetUid::from(1),
mode: ConsensusMode::Auto,
};

assert_eq!(call.encode().first(), Some(&104));
}

#[test]
fn test_sudo_set_alpha_sigmoid_steepness() {
new_test_ext().execute_with(|| {
Expand Down Expand Up @@ -1411,7 +1483,7 @@ fn test_sudo_set_alpha_sigmoid_steepness() {
fn test_set_alpha_values_dispatch_info_ok() {
new_test_ext().execute_with(|| {
let netuid = NetUid::from(1);
let alpha_low: u16 = 1638_u16;
let alpha_low = MIN_ALPHA_LOW;
let alpha_high: u16 = u16::MAX - 10;
let call = RuntimeCall::AdminUtils(crate::Call::sudo_set_alpha_values {
netuid,
Expand All @@ -1430,7 +1502,7 @@ fn test_set_alpha_values_dispatch_info_ok() {
fn test_sudo_get_set_alpha() {
new_test_ext().execute_with(|| {
let netuid = NetUid::from(1);
let alpha_low: u16 = 1638_u16;
let alpha_low = MIN_ALPHA_LOW;
let alpha_high: u16 = u16::MAX - 10;

let hotkey: U256 = U256::from(1);
Expand Down Expand Up @@ -1509,7 +1581,7 @@ fn test_sudo_get_set_alpha() {
));

// 2. Alpha high too low
let alpha_high_too_low = (u16::MAX as u32 / 40) as u16 - 1; // One less than the minimum acceptable value
let alpha_high_too_low = MIN_ALPHA_LOW - 1;
assert_err!(
AdminUtils::sudo_set_alpha_values(
signer.clone(),
Expand All @@ -1528,7 +1600,7 @@ fn test_sudo_get_set_alpha() {
));

// 3. Alpha low too low or too high
let alpha_low_too_low = 0_u16;
let alpha_low_too_low = MIN_ALPHA_LOW - 1;
assert_err!(
AdminUtils::sudo_set_alpha_values(
signer.clone(),
Expand Down
76 changes: 57 additions & 19 deletions pallets/subtensor/src/epoch/run_epoch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ impl<T: Config> Pallet<T> {
terms_sorted.sort_unstable_by_key(|t| t.uid);

let incentive = extract_from_sorted_terms!(terms_sorted, incentive);
let consensus = extract_from_sorted_terms!(terms_sorted, consensus);
let bonds: Vec<Vec<(u16, u16)>> = terms_sorted
.iter()
.cloned()
Expand All @@ -106,6 +107,8 @@ impl<T: Config> Pallet<T> {
// Epoch math stays in raw u16; wrap into PerU16 only at the storage boundary.
let incentive: Vec<PerU16> = incentive.into_iter().map(PerU16::from_parts).collect();
Incentive::<T>::insert(netuid_index, incentive);
let consensus: Vec<PerU16> = consensus.into_iter().map(PerU16::from_parts).collect();
ConsensusByMechanism::<T>::insert(netuid_index, consensus);

let server_emission = extract_from_sorted_terms!(terms_sorted, server_emission);
Self::deposit_event(Event::IncentiveAlphaEmittedToMiners {
Expand Down Expand Up @@ -376,7 +379,7 @@ impl<T: Config> Pallet<T> {
log::trace!("B: {:?}", &bonds);

// Compute the Exponential Moving Average (EMA) of bonds.
ema_bonds = Self::compute_bonds(netuid, &weights_for_bonds, &bonds, &consensus);
ema_bonds = Self::compute_bonds(netuid_index, &weights_for_bonds, &bonds, &consensus);
log::trace!("emaB: {:?}", &ema_bonds);

// Normalize EMA bonds.
Expand Down Expand Up @@ -527,6 +530,14 @@ impl<T: Config> Pallet<T> {
// Epoch math stays in raw u16; wrap into PerU16 only at the storage boundary.
Consensus::<T>::insert(
netuid,
cloned_consensus
.clone()
.into_iter()
.map(PerU16::from_parts)
.collect::<Vec<PerU16>>(),
);
ConsensusByMechanism::<T>::insert(
netuid_index,
cloned_consensus
.into_iter()
.map(PerU16::from_parts)
Expand Down Expand Up @@ -1254,7 +1265,7 @@ impl<T: Config> Pallet<T> {
/// # Arguments
/// * `bonds_delta`: A vector of bond deltas.
/// * `bonds`: A vector of bonds.
/// * `netuid`: The network ID.
/// * `netuid_index`: The mechanism storage index.
///
/// # Returns
/// A vector of EMA bonds.
Expand Down Expand Up @@ -1322,30 +1333,30 @@ impl<T: Config> Pallet<T> {
/// Compute the Exponential Moving Average (EMA) of bonds based on the Liquid Alpha setting
///
/// # Arguments
/// * `netuid`: The network ID.
/// * `netuid_index`: The mechanism storage index.
/// * `weights`: A vector of weights.
/// * `bonds`: A vector of bonds.
/// * `consensus`: A vector of consensus values.
/// * `active_stake`: A vector of active stake values.
///
/// # Returns
/// A vector of EMA bonds.
pub fn compute_bonds(
netuid: NetUid,
netuid_index: NetUidStorageIndex,
weights: &[Vec<I32F32>], // weights_for_bonds
bonds: &[Vec<I32F32>],
consensus: &[I32F32],
) -> Vec<Vec<I32F32>> {
let netuid = Self::get_netuid(netuid_index);

// Check if Liquid Alpha is enabled, consensus is not empty, and contains non-zero values.
if LiquidAlphaOn::<T>::get(netuid)
&& !consensus.is_empty()
&& consensus
.iter()
.any(|&c| c != I32F32::saturating_from_num(0))
{
// Liquid Alpha is enabled, compute the liquid alphas matrix.
let alphas: Vec<Vec<I32F32>> =
Self::compute_liquid_alpha_values(netuid, weights, bonds, consensus);
let consensus = Self::compute_consensus_for_liquid_alpha(netuid_index, consensus);
let alphas = Self::compute_liquid_alpha_values(netuid, weights, bonds, &consensus);
log::trace!("alphas: {:?}", &alphas);

// Compute the Exponential Moving Average (EMA) of bonds using the provided clamped alpha values.
Expand All @@ -1362,11 +1373,10 @@ impl<T: Config> Pallet<T> {
/// Compute the Exponential Moving Average (EMA) of bonds based on the Liquid Alpha setting for a sparse matrix.
///
/// # Arguments
/// * `netuid`: The network ID.
/// * `netuid_index`: The mechanism storage index.
/// * `weights`: A vector of weights.
/// * `bonds`: A vector of bonds.
/// * `consensus`: A vector of consensus values.
/// * `active_stake`: A vector of active stake values.
///
/// # Returns
/// A vector of EMA bonds.
Expand All @@ -1385,9 +1395,9 @@ impl<T: Config> Pallet<T> {
.iter()
.any(|&c| c != I32F32::saturating_from_num(0))
{
// Liquid Alpha is enabled, compute the liquid alphas matrix.
let alphas: Vec<Vec<I32F32>> =
Self::compute_liquid_alpha_values_sparse(netuid, weights, bonds, consensus);
let consensus = Self::compute_consensus_for_liquid_alpha(netuid_index, consensus);
let alphas =
Self::compute_liquid_alpha_values_sparse(netuid, weights, bonds, &consensus);
log::trace!("alphas: {:?}", &alphas);

// Compute the Exponential Moving Average (EMA) of bonds using the provided clamped alpha values.
Expand All @@ -1401,6 +1411,38 @@ impl<T: Config> Pallet<T> {
}
}

pub(crate) fn compute_consensus_for_liquid_alpha(
netuid_index: NetUidStorageIndex,
current: &[I32F32],
) -> Vec<I32F32> {
let netuid = Self::get_netuid(netuid_index);
let use_previous = match Self::get_liquid_alpha_consensus_mode(netuid) {
ConsensusMode::Current => false,
ConsensusMode::Previous => true,
ConsensusMode::Auto => Self::get_bonds_penalty(netuid) == u16::MAX,
};

if !use_previous {
return current.to_vec();
}

let stored = ConsensusByMechanism::<T>::get(netuid_index);
if stored.is_empty() {
return current.to_vec();
}

let mut previous: Vec<I32F32> = stored
.into_iter()
.map(|value| {
I32F32::saturating_from_num(value.deconstruct())
.safe_div(I32F32::saturating_from_num(u16::MAX))
})
.collect();
previous.resize(current.len(), I32F32::from_num(0));
previous.truncate(current.len());
previous
}

/// Compute liquid alphas matrix
/// There is a separate alpha param for each validator-miner binding
///
Expand Down Expand Up @@ -1589,14 +1631,10 @@ impl<T: Config> Pallet<T> {
Error::<T>::LiquidAlphaDisabled
);

let max_u16: u32 = u16::MAX as u32; // 65535
let min_alpha_low: u16 = (max_u16.safe_div(40)) as u16; // 1638
let min_alpha_high: u16 = min_alpha_low;

ensure!(alpha_high >= min_alpha_high, Error::<T>::AlphaHighTooLow);
ensure!(alpha_high >= MIN_ALPHA_LOW, Error::<T>::AlphaHighTooLow);

ensure!(
alpha_low >= min_alpha_low && alpha_low <= alpha_high,
alpha_low >= MIN_ALPHA_LOW && alpha_low <= alpha_high,
Error::<T>::AlphaLowOutOfRange
);

Expand Down
Loading
Loading