Skip to content

Commit

Permalink
fix: disallow regaining weights
Browse files Browse the repository at this point in the history
  • Loading branch information
saiintbrisson committed Feb 9, 2025
1 parent cda934e commit fba1bfd
Show file tree
Hide file tree
Showing 14 changed files with 148 additions and 128 deletions.
4 changes: 4 additions & 0 deletions pallets/emission0/api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![no_std]

use polkadot_sdk::frame_support::dispatch::DispatchResult;

#[derive(Default)]
pub struct ConsensusMemberStats {
pub incentives: u16,
Expand All @@ -11,4 +13,6 @@ pub trait Emission0Api<AccountId> {
/// Returns `None` if the agent has not taken part in the last consensus
/// run.
fn consensus_stats(member: &AccountId) -> Option<ConsensusMemberStats>;

fn delegate_weight_control(delegator: &AccountId, delegatee: &AccountId) -> DispatchResult;
}
14 changes: 13 additions & 1 deletion pallets/emission0/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ pub mod weights;

#[frame::pallet]
pub mod pallet {
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
const STORAGE_VERSION: StorageVersion = StorageVersion::new(2);

use core::num::NonZeroU128;

use frame::prelude::BlockNumberFor;
use frame_system::ensure_signed;
use pallet_governance_api::GovernanceApi;
use pallet_torus0_api::Torus0Api;
use polkadot_sdk::sp_std;
Expand Down Expand Up @@ -145,6 +146,9 @@ pub mod pallet {

/// Agent does not have enough stake to set weights.
NotEnoughStakeToSetWeights,

/// At the current state, agents cannot control their own weight.
WeightControlNotEnabled,
}

#[pallet::event]
Expand Down Expand Up @@ -173,6 +177,7 @@ pub mod pallet {
origin: OriginFor<T>,
target: AccountIdOf<T>,
) -> DispatchResult {
let origin = ensure_signed(origin)?;
weight_control::delegate_weight_control::<T>(origin, target)
}

Expand Down Expand Up @@ -212,4 +217,11 @@ impl<T: Config> Emission0Api<T::AccountId> for Pallet<T> {
}
})
}

fn delegate_weight_control(
delegator: &T::AccountId,
delegatee: &T::AccountId,
) -> DispatchResult {
weight_control::delegate_weight_control::<T>(delegator.clone(), delegatee.clone())
}
}
44 changes: 32 additions & 12 deletions pallets/emission0/src/migrations.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,43 @@
use polkadot_sdk::{
frame_support::{
migrations::VersionedMigration, traits::UncheckedOnRuntimeUpgrade, weights::Weight,
},
sp_runtime::Percent,
use polkadot_sdk::frame_support::{
migrations::VersionedMigration, traits::UncheckedOnRuntimeUpgrade, weights::Weight,
};

use crate::{Config, Pallet};

pub mod v1 {
pub mod v2 {
use polkadot_sdk::sp_std::collections::btree_set::BTreeSet;

use pallet_emission0_api::Emission0Api;
use pallet_governance_api::GovernanceApi;
use pallet_torus0_api::Torus0Api;

use super::*;
use crate::{EmissionRecyclingPercentage, IncentivesRatio};

pub type Migration<T, W> = VersionedMigration<0, 1, MigrateToV1<T>, Pallet<T>, W>;
pub struct MigrateToV1<T>(core::marker::PhantomData<T>);
pub type Migration<T, W> = VersionedMigration<1, 2, MigrateToV2<T>, Pallet<T>, W>;
pub struct MigrateToV2<T>(core::marker::PhantomData<T>);

impl<T: Config> UncheckedOnRuntimeUpgrade for MigrateToV1<T> {
impl<T: Config> UncheckedOnRuntimeUpgrade for MigrateToV2<T> {
fn on_runtime_upgrade() -> Weight {
EmissionRecyclingPercentage::<T>::set(Percent::from_percent(81));
IncentivesRatio::<T>::set(Percent::from_percent(30));
let allocators: BTreeSet<_> = <T::Governance>::get_allocators().collect();
if let Some(allocator) = allocators.first() {
for agent in <T::Torus>::agent_ids() {
if allocators.contains(&agent) {
continue;
}

if let Err(err) =
<Pallet<T> as Emission0Api<T::AccountId>>::delegate_weight_control(
&agent, allocator,
)
{
polkadot_sdk::sp_tracing::error!(
"failed to delegate weight control from {agent:?} to {allocator:?}: {err:?}"
);
}
}
} else {
polkadot_sdk::sp_tracing::error!("no allocators available");
}

Weight::zero()
}
Expand Down
24 changes: 14 additions & 10 deletions pallets/emission0/src/weight_control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,40 +66,44 @@ pub fn set_weights<T: crate::Config>(
}

pub fn delegate_weight_control<T: crate::Config>(
origin: OriginFor<T>,
target: T::AccountId,
delegator: T::AccountId,
delegatee: T::AccountId,
) -> DispatchResult {
let acc_id = ensure_signed(origin)?;

ensure!(
acc_id != target,
delegator != delegatee,
crate::Error::<T>::CannotDelegateWeightControlToSelf,
);

ensure!(
<T::Torus>::is_agent_registered(&acc_id),
<T::Torus>::is_agent_registered(&delegator),
crate::Error::<T>::AgentIsNotRegistered
);

ensure!(
<T::Torus>::is_agent_registered(&target),
<T::Torus>::is_agent_registered(&delegatee),
crate::Error::<T>::AgentIsNotRegistered
);

// At the current network stage, it only makes sense to delegate weight control
// to allocators.
<T::Governance>::ensure_allocator(&target)?;
<T::Governance>::ensure_allocator(&delegatee)?;

crate::WeightControlDelegation::<T>::set(&acc_id, Some(target.clone()));
crate::WeightControlDelegation::<T>::set(&delegator, Some(delegatee.clone()));

crate::Pallet::<T>::deposit_event(crate::Event::<T>::DelegatedWeightControl(acc_id, target));
crate::Pallet::<T>::deposit_event(crate::Event::<T>::DelegatedWeightControl(
delegator, delegatee,
));

Ok(())
}

pub fn regain_weight_control<T: crate::Config>(origin: OriginFor<T>) -> DispatchResult {
let acc_id = ensure_signed(origin)?;

if <T::Governance>::ensure_allocator(&acc_id).is_err() {
return Err(crate::Error::<T>::WeightControlNotEnabled.into());
}

crate::WeightControlDelegation::<T>::mutate(acc_id, |val| match val.take() {
Some(_) => Ok(()),
None => Err(crate::Error::<T>::AgentIsNotDelegating.into()),
Expand Down
4 changes: 2 additions & 2 deletions pallets/emission0/tests/distribution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use polkadot_sdk::{
};
use substrate_fixed::{traits::ToFixed, types::I96F32};
use test_utils::{
add_balance, add_stake, get_origin,
add_balance, add_stake,
pallet_governance::{Allocators, TreasuryEmissionFee},
pallet_torus0::{
stake::sum_staked_by, Agents, FeeConstraints, MaxAllowedValidators, MinAllowedStake,
Expand Down Expand Up @@ -491,7 +491,7 @@ fn pays_weight_control_fee_and_dividends_to_stakers() {

Allocators::<Test>::set(val_1, Some(()));

pallet_emission0::weight_control::delegate_weight_control::<Test>(get_origin(val_2), val_1)
pallet_emission0::weight_control::delegate_weight_control::<Test>(val_2, val_1)
.expect("failed to delegate weight control");

let val_1_staker = 3;
Expand Down
33 changes: 20 additions & 13 deletions pallets/emission0/tests/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,47 +14,55 @@ fn delegates_and_regains_weight_control() {
let delegated = 1;

assert_eq!(
delegate_weight_control::<Test>(get_origin(delegator), delegator),
delegate_weight_control::<Test>(delegator, delegator),
Err(Error::<Test>::CannotDelegateWeightControlToSelf.into())
);

assert_eq!(
delegate_weight_control::<Test>(get_origin(delegator), delegated),
delegate_weight_control::<Test>(delegator, delegated),
Err(Error::<Test>::AgentIsNotRegistered.into())
);

assert_eq!(
regain_weight_control::<Test>(get_origin(delegator)),
Err(Error::<Test>::AgentIsNotDelegating.into())
);
// TODO: reenable when weight control is enabled again
// assert_eq!(
// regain_weight_control::<Test>(get_origin(delegator)),
// Err(Error::<Test>::AgentIsNotDelegating.into())
// );

register_empty_agent(delegator);

assert_eq!(
delegate_weight_control::<Test>(get_origin(delegator), delegated),
delegate_weight_control::<Test>(delegator, delegated),
Err(Error::<Test>::AgentIsNotRegistered.into())
);

register_empty_agent(delegated);

delegate_weight_control::<Test>(get_origin(delegator), delegated)
delegate_weight_control::<Test>(delegator, delegated)
.expect_err("cannot delegate to not-allocator");

Allocators::<Test>::set(delegated, Some(()));

assert_eq!(
delegate_weight_control::<Test>(get_origin(delegator), delegated),
delegate_weight_control::<Test>(delegator, delegated),
Ok(())
);

assert!(WeightControlDelegation::<Test>::contains_key(delegator));

assert_eq!(regain_weight_control::<Test>(get_origin(delegator)), Ok(()));
assert!(!WeightControlDelegation::<Test>::contains_key(delegator));
assert_eq!(
regain_weight_control::<Test>(get_origin(delegator)),
Err(Error::<Test>::WeightControlNotEnabled.into())
);

// TODO: reenable when weight control is enabled
// assert_eq!(regain_weight_control::<Test>(get_origin(delegator)), Ok(()));
// assert!(!WeightControlDelegation::<Test>::contains_key(delegator));
});
}

#[test]
#[allow(unreachable_code)]
fn sets_weights_correctly() {
test_utils::new_test_ext().execute_with(|| {
let validator = 0;
Expand Down Expand Up @@ -95,8 +103,7 @@ fn sets_weights_correctly() {

Allocators::<Test>::set(1, Some(()));

delegate_weight_control::<Test>(get_origin(validator), 1)
.expect("failed to delegate weight control");
delegate_weight_control::<Test>(validator, 1).expect("failed to delegate weight control");

assert_eq!(
set_weights::<Test>(get_origin(validator), vec![(1, 0); 5]),
Expand Down
2 changes: 2 additions & 0 deletions pallets/governance/api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ pub trait GovernanceApi<AccountId> {

fn ensure_allocator(key: &AccountId) -> DispatchResult;

fn get_allocators() -> impl Iterator<Item = AccountId>;

fn set_allocator(key: &AccountId);
}
6 changes: 5 additions & 1 deletion pallets/governance/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ use crate::{
pub mod pallet {
#![allow(clippy::too_many_arguments)]

const STORAGE_VERSION: StorageVersion = StorageVersion::new(2);
const STORAGE_VERSION: StorageVersion = StorageVersion::new(3);

use proposal::GlobalParamsData;
use weights::WeightInfo;
Expand Down Expand Up @@ -533,6 +533,10 @@ impl<T: Config> pallet_governance_api::GovernanceApi<T::AccountId> for Pallet<T>
crate::roles::ensure_allocator::<T>(key)
}

fn get_allocators() -> impl Iterator<Item = T::AccountId> {
Allocators::<T>::iter_keys()
}

fn set_allocator(key: &T::AccountId) {
crate::Allocators::<T>::insert(key, ());
}
Expand Down
36 changes: 6 additions & 30 deletions pallets/governance/src/migrations.rs
Original file line number Diff line number Diff line change
@@ -1,41 +1,17 @@
use polkadot_sdk::{
frame_support::{
migrations::VersionedMigration, traits::UncheckedOnRuntimeUpgrade, weights::Weight,
},
sp_runtime::Percent,
use polkadot_sdk::frame_support::{
migrations::VersionedMigration, traits::UncheckedOnRuntimeUpgrade, weights::Weight,
};

use crate::{Config, Pallet};

pub type Migrations<T, W> = (v1::Migration<T, W>, v2::Migration<T, W>);

pub mod v2 {
use super::*;
use crate::TreasuryEmissionFee;

pub type Migration<T, W> = VersionedMigration<1, 2, MigrateToV2<T>, Pallet<T>, W>;
pub struct MigrateToV2<T>(core::marker::PhantomData<T>);

impl<T: Config> UncheckedOnRuntimeUpgrade for MigrateToV2<T> {
fn on_runtime_upgrade() -> Weight {
// Set Treasury emission fee to 5%
TreasuryEmissionFee::<T>::put(Percent::from_percent(5));

Weight::zero()
}
}
}

pub mod v1 {
pub mod v3 {
use super::*;
use crate::GlobalGovernanceConfig;

pub type Migration<T, W> = VersionedMigration<0, 1, MigrateToV1<T>, Pallet<T>, W>;
pub struct MigrateToV1<T>(core::marker::PhantomData<T>);
pub type Migration<T, W> = VersionedMigration<2, 3, MigrateToV3<T>, Pallet<T>, W>;
pub struct MigrateToV3<T>(core::marker::PhantomData<T>);

impl<T: Config> UncheckedOnRuntimeUpgrade for MigrateToV1<T> {
impl<T: Config> UncheckedOnRuntimeUpgrade for MigrateToV3<T> {
fn on_runtime_upgrade() -> Weight {
GlobalGovernanceConfig::<T>::put(crate::config::GovernanceConfiguration::default());
Weight::zero()
}
}
Expand Down
14 changes: 13 additions & 1 deletion pallets/torus0/src/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,19 @@ pub fn register<T: crate::Config>(
crate::RegistrationsThisBlock::<T>::mutate(|value| value.saturating_add(1));
crate::RegistrationsThisInterval::<T>::mutate(|value| value.saturating_add(1));

crate::Pallet::<T>::deposit_event(crate::Event::<T>::AgentRegistered(agent_key));
crate::Pallet::<T>::deposit_event(crate::Event::<T>::AgentRegistered(agent_key.clone()));

if let Some(allocator) = <T::Governance>::get_allocators().next() {
if let Err(err) = <T::Emission>::delegate_weight_control(&agent_key, &allocator) {
polkadot_sdk::sp_tracing::error!(
"failed to delegate weight control for {agent_key:?} on {allocator:?}: {err:?}"
);
}
} else {
polkadot_sdk::sp_tracing::error!(
"no allocators available to delegate to for {agent_key:?}"
);
}

Ok(())
}
Expand Down
25 changes: 2 additions & 23 deletions pallets/torus0/src/migrations.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,9 @@
use polkadot_sdk::{
frame_support::{
migrations::VersionedMigration, traits::UncheckedOnRuntimeUpgrade, weights::Weight,
},
sp_runtime::Percent,
use polkadot_sdk::frame_support::{
migrations::VersionedMigration, traits::UncheckedOnRuntimeUpgrade, weights::Weight,
};

use crate::{Config, Pallet};

pub mod v1 {
use super::*;
use crate::{Agent, Agents};

pub type Migration<T, W> = VersionedMigration<0, 1, MigrateToV1<T>, Pallet<T>, W>;
pub struct MigrateToV1<T>(core::marker::PhantomData<T>);

impl<T: Config> UncheckedOnRuntimeUpgrade for MigrateToV1<T> {
fn on_runtime_upgrade() -> Weight {
Agents::<T>::translate(|_key, mut agent: Agent<T>| {
agent.weight_penalty_factor = Percent::from_percent(0);
Some(agent)
});
Weight::zero()
}
}
}

pub mod v2 {
use super::*;
use crate::{Agent, Agents};
Expand Down
Loading

0 comments on commit fba1bfd

Please sign in to comment.