Skip to content

Commit 06ec269

Browse files
feat: add cooldown and event to agent update extrinsic (#88)
Closes CHAIN-66 --------- Co-authored-by: Luiz Carvalho <[email protected]>
1 parent df671d1 commit 06ec269

File tree

8 files changed

+337
-20
lines changed

8 files changed

+337
-20
lines changed

pallets/governance/src/migrations.rs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,127 @@ use polkadot_sdk::frame_support::{
55
use crate::{Config, Pallet};
66

77
pub mod v3 {
8+
use crate::proposal::{GlobalParamsData, ProposalData};
9+
810
use super::*;
911

1012
pub type Migration<T, W> = VersionedMigration<2, 3, MigrateToV3<T>, Pallet<T>, W>;
1113
pub struct MigrateToV3<T>(core::marker::PhantomData<T>);
1214

15+
mod old_storage {
16+
use codec::{Decode, Encode, MaxEncodedLen};
17+
use polkadot_sdk::{
18+
frame_support::{storage_alias, DebugNoBound, Identity},
19+
polkadot_sdk_frame::prelude::BlockNumberFor,
20+
sp_core::ConstU32,
21+
sp_runtime::{BoundedVec, Percent},
22+
};
23+
use scale_info::TypeInfo;
24+
25+
use crate::{
26+
proposal::{ProposalId, ProposalStatus},
27+
AccountIdOf, BalanceOf,
28+
};
29+
30+
#[derive(Clone, DebugNoBound, TypeInfo, Decode, Encode, MaxEncodedLen)]
31+
#[scale_info(skip_type_params(T))]
32+
pub struct Proposal<T: crate::Config> {
33+
pub id: ProposalId,
34+
pub proposer: AccountIdOf<T>,
35+
pub expiration_block: BlockNumberFor<T>,
36+
pub data: ProposalData<T>,
37+
pub status: ProposalStatus<T>,
38+
pub metadata: BoundedVec<u8, ConstU32<256>>,
39+
pub proposal_cost: BalanceOf<T>,
40+
pub creation_block: BlockNumberFor<T>,
41+
}
42+
43+
#[derive(Clone, DebugNoBound, TypeInfo, Decode, Encode, MaxEncodedLen, PartialEq, Eq)]
44+
#[scale_info(skip_type_params(T))]
45+
pub enum ProposalData<T: crate::Config> {
46+
GlobalParams(GlobalParamsData<T>),
47+
GlobalCustom,
48+
Emission {
49+
recycling_percentage: Percent,
50+
treasury_percentage: Percent,
51+
incentives_ratio: Percent,
52+
},
53+
TransferDaoTreasury {
54+
account: AccountIdOf<T>,
55+
amount: BalanceOf<T>,
56+
},
57+
}
58+
59+
#[derive(Clone, DebugNoBound, TypeInfo, Decode, Encode, MaxEncodedLen, PartialEq, Eq)]
60+
#[scale_info(skip_type_params(T))]
61+
pub struct GlobalParamsData<T: crate::Config> {
62+
pub min_name_length: u16,
63+
pub max_name_length: u16,
64+
pub max_allowed_agents: u16,
65+
pub max_allowed_weights: u16,
66+
pub min_stake_per_weight: BalanceOf<T>,
67+
pub min_weight_control_fee: u8,
68+
pub min_staking_fee: u8,
69+
pub dividends_participation_weight: Percent,
70+
pub proposal_cost: BalanceOf<T>,
71+
}
72+
73+
#[storage_alias]
74+
pub type Proposals<T: crate::Config> =
75+
StorageMap<crate::Pallet<T>, Identity, ProposalId, Proposal<T>>;
76+
}
77+
1378
impl<T: Config> UncheckedOnRuntimeUpgrade for MigrateToV3<T> {
1479
fn on_runtime_upgrade() -> Weight {
80+
for (id, proposal) in old_storage::Proposals::iter() {
81+
let new_data = match proposal.data {
82+
old_storage::ProposalData::GlobalParams(old_storage::GlobalParamsData {
83+
min_name_length,
84+
max_name_length,
85+
max_allowed_agents,
86+
min_weight_control_fee,
87+
min_staking_fee,
88+
dividends_participation_weight,
89+
proposal_cost,
90+
..
91+
}) => ProposalData::GlobalParams(GlobalParamsData {
92+
min_name_length,
93+
max_name_length,
94+
max_allowed_agents,
95+
min_weight_control_fee,
96+
min_staking_fee,
97+
dividends_participation_weight,
98+
proposal_cost,
99+
}),
100+
old_storage::ProposalData::GlobalCustom => ProposalData::GlobalCustom,
101+
old_storage::ProposalData::Emission {
102+
recycling_percentage,
103+
treasury_percentage,
104+
incentives_ratio,
105+
} => ProposalData::Emission {
106+
recycling_percentage,
107+
treasury_percentage,
108+
incentives_ratio,
109+
},
110+
old_storage::ProposalData::TransferDaoTreasury { account, amount } => {
111+
ProposalData::TransferDaoTreasury { account, amount }
112+
}
113+
};
114+
115+
let new_proposal = crate::proposal::Proposal {
116+
id: proposal.id,
117+
proposer: proposal.proposer,
118+
expiration_block: proposal.expiration_block,
119+
data: new_data,
120+
status: proposal.status,
121+
metadata: proposal.metadata,
122+
proposal_cost: proposal.proposal_cost,
123+
creation_block: proposal.creation_block,
124+
};
125+
126+
crate::Proposals::<T>::set(id, Some(new_proposal));
127+
}
128+
15129
Weight::zero()
16130
}
17131
}

pallets/torus0/src/agent.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub struct Agent<T: crate::Config> {
3636
pub weight_penalty_factor: Percent,
3737
pub registration_block: BlockNumberFor<T>,
3838
pub fees: crate::fee::ValidatorFee<T>,
39+
pub last_update_block: BlockNumberFor<T>,
3940
}
4041

4142
/// Register an agent to the given key, payed by the payer key.
@@ -108,6 +109,7 @@ pub fn register<T: crate::Config>(
108109
)
109110
.map_err(|_| crate::Error::<T>::NotEnoughBalanceToRegisterAgent)?;
110111

112+
let registration_block = <polkadot_sdk::frame_system::Pallet<T>>::block_number();
111113
crate::Agents::<T>::insert(
112114
agent_key.clone(),
113115
Agent {
@@ -116,8 +118,9 @@ pub fn register<T: crate::Config>(
116118
url: BoundedVec::truncate_from(url),
117119
metadata: BoundedVec::truncate_from(metadata),
118120
weight_penalty_factor: Percent::from_percent(0),
119-
registration_block: <polkadot_sdk::frame_system::Pallet<T>>::block_number(),
121+
registration_block,
120122
fees: Default::default(),
123+
last_update_block: registration_block,
121124
},
122125
);
123126

@@ -177,6 +180,10 @@ pub fn update<T: crate::Config>(
177180
return Err(crate::Error::<T>::AgentDoesNotExist.into());
178181
};
179182

183+
if is_in_update_cooldown::<T>(&agent_key)? {
184+
return Err(crate::Error::<T>::AgentUpdateOnCooldown.into());
185+
}
186+
180187
validate_agent_name::<T>(&name[..])?;
181188
agent.name = BoundedVec::truncate_from(name);
182189

@@ -211,9 +218,35 @@ pub fn update<T: crate::Config>(
211218
Ok::<(), DispatchError>(())
212219
})?;
213220

221+
set_in_cooldown::<T>(&agent_key)?;
222+
crate::Pallet::<T>::deposit_event(crate::Event::<T>::AgentUpdated(agent_key));
223+
214224
Ok(())
215225
}
216226

227+
fn is_in_update_cooldown<T: crate::Config>(key: &AccountIdOf<T>) -> Result<bool, DispatchError> {
228+
let current_block = <polkadot_sdk::frame_system::Pallet<T>>::block_number();
229+
let cooldown = crate::AgentUpdateCooldown::<T>::get();
230+
231+
let last_update = crate::Agents::<T>::get(key)
232+
.ok_or(crate::Error::<T>::AgentDoesNotExist)?
233+
.last_update_block;
234+
235+
Ok(last_update + cooldown > current_block)
236+
}
237+
238+
fn set_in_cooldown<T: crate::Config>(key: &AccountIdOf<T>) -> DispatchResult {
239+
crate::Agents::<T>::mutate(key, |agent| {
240+
let Some(agent) = agent else {
241+
return Err(crate::Error::<T>::AgentDoesNotExist.into());
242+
};
243+
244+
agent.last_update_block = <polkadot_sdk::frame_system::Pallet<T>>::block_number();
245+
246+
Ok(())
247+
})
248+
}
249+
217250
pub fn exists<T: crate::Config>(key: &AccountIdOf<T>) -> bool {
218251
crate::Agents::<T>::contains_key(key)
219252
}

pallets/torus0/src/lib.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ pub mod migrations;
88
pub mod stake;
99

1010
pub(crate) use ext::*;
11-
use frame::{arithmetic::Percent, prelude::ensure_signed};
11+
use frame::{
12+
arithmetic::Percent,
13+
prelude::{ensure_root, ensure_signed},
14+
};
1215
pub use pallet::*;
1316
use polkadot_sdk::{
1417
frame_support::{
@@ -26,7 +29,7 @@ use crate::{agent::Agent, burn::BurnConfiguration, fee::ValidatorFeeConstraints}
2629

2730
#[frame::pallet]
2831
pub mod pallet {
29-
const STORAGE_VERSION: StorageVersion = StorageVersion::new(2);
32+
const STORAGE_VERSION: StorageVersion = StorageVersion::new(3);
3033

3134
use frame::prelude::BlockNumberFor;
3235
use pallet_emission0_api::Emission0Api;
@@ -132,6 +135,11 @@ pub mod pallet {
132135
#[pallet::storage]
133136
pub type BurnConfig<T: Config> = StorageValue<_, BurnConfiguration<T>, ValueQuery>;
134137

138+
/// Cooldown (in blocks) in which an agent needs to wait between each `update_agent` call.
139+
#[pallet::storage]
140+
pub type AgentUpdateCooldown<T: Config> =
141+
StorageValue<_, BlockNumberFor<T>, ValueQuery, T::DefaultAgentUpdateCooldown>;
142+
135143
#[pallet::hooks]
136144
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
137145
fn on_initialize(block_number: BlockNumberFor<T>) -> Weight {
@@ -228,6 +236,11 @@ pub mod pallet {
228236
#[pallet::constant]
229237
type DefaultDividendsParticipationWeight: Get<Percent>;
230238

239+
/// Default Cooldown (in blocks) in which an agent needs to wait between each `update_agent` call.
240+
#[pallet::constant]
241+
#[pallet::no_default_bounds]
242+
type DefaultAgentUpdateCooldown: Get<BlockNumberFor<Self>>;
243+
231244
#[pallet::no_default_bounds]
232245
type RuntimeEvent: From<Event<Self>>
233246
+ IsType<<Self as polkadot_sdk::frame_system::Config>::RuntimeEvent>;
@@ -329,6 +342,18 @@ pub mod pallet {
329342
weight_control_fee,
330343
)
331344
}
345+
346+
/// Updates origin's key agent metadata.
347+
#[pallet::call_index(6)]
348+
#[pallet::weight((Weight::zero(), DispatchClass::Normal, Pays::Yes))]
349+
pub fn set_agent_update_cooldown(
350+
origin: OriginFor<T>,
351+
new_cooldown: BlockNumberFor<T>,
352+
) -> DispatchResult {
353+
ensure_root(origin)?;
354+
AgentUpdateCooldown::<T>::set(new_cooldown);
355+
Ok(())
356+
}
332357
}
333358

334359
#[pallet::event]
@@ -428,6 +453,8 @@ pub mod pallet {
428453
InvalidStakingFee,
429454
/// The weight control fee given is lower than the minimum fee
430455
InvalidWeightControlFee,
456+
/// The agent already updated recently
457+
AgentUpdateOnCooldown,
431458
}
432459
}
433460

@@ -516,6 +543,7 @@ impl<T: Config>
516543
weight_penalty_factor: Default::default(),
517544
registration_block: Default::default(),
518545
fees: Default::default(),
546+
last_update_block: Default::default(),
519547
}),
520548
);
521549

pallets/torus0/src/migrations.rs

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,60 @@ use polkadot_sdk::frame_support::{
44

55
use crate::{Config, Pallet};
66

7-
pub mod v2 {
7+
pub mod v3 {
88
use super::*;
99
use crate::{Agent, Agents};
10-
pub type Migration<T, W> = VersionedMigration<1, 2, MigrateToV1<T>, Pallet<T>, W>;
11-
pub struct MigrateToV1<T>(core::marker::PhantomData<T>);
12-
impl<T: Config> UncheckedOnRuntimeUpgrade for MigrateToV1<T> {
10+
use scale_info::prelude::vec::Vec;
11+
12+
pub mod storage {
13+
use codec::{Decode, Encode, MaxEncodedLen};
14+
use polkadot_sdk::frame_support::{storage_alias, DebugNoBound, Identity};
15+
use polkadot_sdk::polkadot_sdk_frame::prelude::BlockNumberFor;
16+
use polkadot_sdk::sp_runtime::{BoundedVec, Percent};
17+
use scale_info::TypeInfo;
18+
19+
use crate::AccountIdOf;
20+
21+
#[derive(DebugNoBound, Encode, Decode, MaxEncodedLen, TypeInfo)]
22+
#[scale_info(skip_type_params(T))]
23+
pub struct Agent<T: crate::Config> {
24+
pub key: AccountIdOf<T>,
25+
pub name: BoundedVec<u8, T::MaxAgentNameLengthConstraint>,
26+
pub url: BoundedVec<u8, T::MaxAgentUrlLengthConstraint>,
27+
pub metadata: BoundedVec<u8, T::MaxAgentMetadataLengthConstraint>,
28+
pub weight_penalty_factor: Percent,
29+
pub registration_block: BlockNumberFor<T>,
30+
pub fees: crate::fee::ValidatorFee<T>,
31+
}
32+
33+
#[storage_alias]
34+
pub type Agents<T: crate::Config> =
35+
StorageMap<crate::Pallet<T>, Identity, AccountIdOf<T>, Agent<T>>;
36+
}
37+
38+
pub type Migration<T, W> = VersionedMigration<2, 3, MigrateToV3<T>, Pallet<T>, W>;
39+
pub struct MigrateToV3<T>(core::marker::PhantomData<T>);
40+
impl<T: Config> UncheckedOnRuntimeUpgrade for MigrateToV3<T> {
1341
fn on_runtime_upgrade() -> Weight {
14-
Agents::<T>::translate(|_key, mut agent: Agent<T>| {
15-
agent.fees = Default::default();
16-
Some(agent)
17-
});
42+
let old_agents = storage::Agents::<T>::iter().collect::<Vec<_>>();
43+
let _ = storage::Agents::<T>::clear(u32::MAX, None);
44+
45+
for (id, old_agent) in old_agents {
46+
Agents::<T>::insert(
47+
id,
48+
Agent {
49+
key: old_agent.key,
50+
name: old_agent.name,
51+
url: old_agent.url,
52+
metadata: old_agent.metadata,
53+
registration_block: old_agent.registration_block,
54+
weight_penalty_factor: old_agent.weight_penalty_factor,
55+
fees: old_agent.fees,
56+
last_update_block: old_agent.registration_block,
57+
},
58+
)
59+
}
60+
1861
Weight::zero()
1962
}
2063
}

0 commit comments

Comments
 (0)