Skip to content

Commit

Permalink
Rate limit
Browse files Browse the repository at this point in the history
  • Loading branch information
aurexav committed Apr 15, 2024
1 parent 0bf4278 commit 8ef837a
Show file tree
Hide file tree
Showing 12 changed files with 133 additions and 12 deletions.
2 changes: 2 additions & 0 deletions node/src/chain_spec/crab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ pub fn genesis_config() -> ChainSpec {
darwinia_staking: DarwiniaStakingConfig {
now: SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis(),
elapsed_time: 0,
max_unstake_ring: 10_000_000 * UNIT,
collator_count: 6,
collators: collators
.iter()
Expand Down Expand Up @@ -303,6 +304,7 @@ fn testnet_genesis(
darwinia_staking: DarwiniaStakingConfig {
now: SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis(),
elapsed_time: 0,
max_unstake_ring: 10_000_000 * UNIT,
collator_count: collators.len() as _,
collators: collators.iter().map(|(a, _)| (a.to_owned(), UNIT)).collect(),
},
Expand Down
2 changes: 2 additions & 0 deletions node/src/chain_spec/darwinia.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ pub fn genesis_config() -> ChainSpec {
darwinia_staking: DarwiniaStakingConfig {
now: SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis(),
elapsed_time: 0,
max_unstake_ring: 10_000_000 * UNIT,
collator_count: 5,
collators: collators
.iter()
Expand Down Expand Up @@ -301,6 +302,7 @@ fn testnet_genesis(
darwinia_staking: DarwiniaStakingConfig {
now: SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis(),
elapsed_time: 0,
max_unstake_ring: 10_000_000 * UNIT,
collator_count: collators.len() as _,
collators: collators.iter().map(|(a, _)| (a.to_owned(), UNIT)).collect(),
},
Expand Down
9 changes: 9 additions & 0 deletions pallet/staking/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,15 @@ mod benchmarks {
_(RawOrigin::Signed(sender), a);
}

#[benchmark]
fn set_max_unstake_ring() {
// Worst-case scenario:
//
// Set max unstake ring successfully.
#[extrinsic_call]
_(RawOrigin::Root, 1);
}

#[benchmark]
fn set_collator_count() {
// Worst-case scenario:
Expand Down
42 changes: 40 additions & 2 deletions pallet/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,8 @@ pub mod pallet {
pub enum Error<T> {
/// Exceed maximum deposit count.
ExceedMaxDeposits,
/// Exceed maximum unstaking/unbonding count.
ExceedMaxUnstakings,
/// Exceed maximum unstake amount.
ExceedMaxUnstakeAmount,
/// Deposit not found.
DepositNotFound,
/// You are not a staker.
Expand Down Expand Up @@ -282,13 +282,29 @@ pub mod pallet {
#[pallet::getter(fn elapsed_time)]
pub type ElapsedTime<T: Config> = StorageValue<_, Moment, ValueQuery>;

/// Max unstake RING limit.
///
/// The maximum RING amount that can be unstaked in a session.
#[pallet::storage]
#[pallet::getter(fn max_unstake_ring)]
pub type MaxUnstakeRing<T: Config> = StorageValue<_, Balance, ValueQuery>;

/// Unstake accumulator.
///
/// Tracks the total RING amount being unstaked in a session.
#[pallet::storage]
#[pallet::getter(fn accumulate_unstake)]
pub type AccumulateUnstake<T: Config> = StorageValue<_, Balance, ValueQuery>;

#[derive(DefaultNoBound)]
#[pallet::genesis_config]
pub struct GenesisConfig<T: Config> {
/// Current timestamp.
pub now: Moment,
/// The running time of Darwinia1.
pub elapsed_time: Moment,
/// Max unstake RING limit.
pub max_unstake_ring: Balance,
/// Genesis collator count.
pub collator_count: u32,
/// Genesis collator preferences.
Expand All @@ -304,6 +320,7 @@ pub mod pallet {

<SessionStartTime<T>>::put(self.now);
<ElapsedTime<T>>::put(self.elapsed_time);
<MaxUnstakeRing<T>>::put(self.max_unstake_ring);
<CollatorCount<T>>::put(self.collator_count);

self.collators.iter().for_each(|(who, ring_amount)| {
Expand Down Expand Up @@ -400,6 +417,8 @@ pub mod pallet {
return Ok(());
}

let mut acc = <AccumulateUnstake<T>>::get().saturating_add(ring_amount);

<Ledgers<T>>::try_mutate(&who, |l| {
let l = l.as_mut().ok_or(<Error<T>>::NotStaker)?;

Expand All @@ -413,6 +432,8 @@ pub mod pallet {
}

for d in deposits {
acc = acc.saturating_add(T::Deposit::amount(&who, d).unwrap_or_default());

l.deposits.remove(
l.deposits
.iter()
Expand All @@ -426,6 +447,12 @@ pub mod pallet {
DispatchResult::Ok(())
})?;

if acc <= <MaxUnstakeRing<T>>::get() {
<AccumulateUnstake<T>>::put(acc);
} else {
Err(<Error<T>>::ExceedMaxUnstakeAmount)?;
}

Self::try_clean_ledger_of(&who);

Ok(())
Expand Down Expand Up @@ -493,6 +520,17 @@ pub mod pallet {
Ok(())
}

/// Set max unstake RING limit.
#[pallet::call_index(9)]
#[pallet::weight(<T as Config>::WeightInfo::set_max_unstake_ring())]
pub fn set_max_unstake_ring(origin: OriginFor<T>, amount: Balance) -> DispatchResult {
ensure_root(origin)?;

<MaxUnstakeRing<T>>::put(amount);

Ok(())
}

/// Set collator count.
///
/// This will apply to the incoming session.
Expand Down
4 changes: 3 additions & 1 deletion pallet/staking/src/migration/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use core::marker::PhantomData;
// darwinia
use crate::*;
use dc_types::UNIT;
// substrate
use frame_support::traits::OnRuntimeUpgrade;
#[cfg(feature = "try-runtime")]
Expand Down Expand Up @@ -77,11 +78,12 @@ where
return T::DbWeight::get().reads(r);
}

let mut w = 4;
let mut w = 5;

<RingPool<T>>::kill();
<KtonPool<T>>::kill();
<MigrationStartBlock<T>>::kill();
<MaxUnstakeRing<T>>::put(10_000_000 * UNIT);
<Ledgers<T>>::translate::<OldLedger<T>, _>(|a, o| {
w += 6;

Expand Down
1 change: 1 addition & 0 deletions pallet/staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ impl ExtBuilder {
.assimilate_storage(&mut storage)
.unwrap();
darwinia_staking::GenesisConfig::<Runtime> {
max_unstake_ring: 100 * UNIT,
collator_count: self.collator_count,
collators: if self.genesis_collator {
(1..=self.collator_count).map(|i| (i, UNIT)).collect()
Expand Down
49 changes: 46 additions & 3 deletions pallet/staking/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ fn unstake_should_work() {

// Unstake 1 RING.
assert_ok!(Staking::unstake(RuntimeOrigin::signed(1), UNIT, Vec::new()));
assert_eq!(Staking::accumulate_unstake(), UNIT);
assert_eq!(Balances::free_balance(1), 995 * UNIT);
assert_eq!(
Staking::ledger_of(1).unwrap(),
Expand All @@ -214,6 +215,7 @@ fn unstake_should_work() {
// Unstake 1 deposit.
Efflux::block(1);
assert_ok!(Staking::unstake(RuntimeOrigin::signed(1), 0, vec![1]));
assert_eq!(Staking::accumulate_unstake(), 2 * UNIT);
assert_eq!(
Staking::ledger_of(1).unwrap(),
Ledger { ring: 2 * UNIT, deposits: BoundedVec::truncate_from(vec![0, 2]) }
Expand Down Expand Up @@ -250,17 +252,58 @@ fn unstake_should_work() {
// Unstake 2 RING and 2 deposits.
Efflux::block(1);
assert_ok!(Staking::unstake(RuntimeOrigin::signed(1), 2 * UNIT, vec![0, 2]));
assert_eq!(Staking::accumulate_unstake(), 6 * UNIT);
assert!(Staking::ledger_of(1).is_none());
assert_eq!(
Deposit::deposit_of(1).unwrap(),
<BoundedVec<_, <Runtime as darwinia_deposit::Config>::MaxDeposits>>::truncate_from(
vec![
DepositS { id: 0, value: UNIT, start_time: 3, expired_time: 2635200003, in_use: false },
DepositS { id: 1, value: UNIT, start_time: 3, expired_time: 2635200003, in_use: false },
DepositS { id: 2, value: UNIT, start_time: 3, expired_time: 2635200003, in_use: false }
DepositS {
id: 0,
value: UNIT,
start_time: 3,
expired_time: 2635200003,
in_use: false
},
DepositS {
id: 1,
value: UNIT,
start_time: 3,
expired_time: 2635200003,
in_use: false
},
DepositS {
id: 2,
value: UNIT,
start_time: 3,
expired_time: 2635200003,
in_use: false
}
]
)
);

// Prepare rate limit test data.
assert_ok!(Deposit::lock(RuntimeOrigin::signed(1), 94 * UNIT + 1, 1));
assert_ok!(Staking::stake(RuntimeOrigin::signed(1), 94 * UNIT + 1, vec![3]));

// Unstake 94 UNIT + 1.
assert_noop!(
Staking::unstake(RuntimeOrigin::signed(1), 94 * UNIT + 1, Vec::new()),
<Error<Runtime>>::ExceedMaxUnstakeAmount
);

// Unstake 94 UNIT + 1.
assert_noop!(
Staking::unstake(RuntimeOrigin::signed(1), 0, vec![3]),
<Error<Runtime>>::ExceedMaxUnstakeAmount
);

// Unstake RING(94 UNIT + 1) and deposit(94 UNIT + 1).
assert_noop!(
Staking::unstake(RuntimeOrigin::signed(1), 94 * UNIT + 1, vec![3]),
<Error<Runtime>>::ExceedMaxUnstakeAmount
);
});
}

Expand Down
7 changes: 7 additions & 0 deletions pallet/staking/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub trait WeightInfo {
fn nominate() -> Weight;
fn chill() -> Weight;
fn payout() -> Weight;
fn set_max_unstake_ring() -> Weight;
fn set_collator_count() -> Weight;
}

Expand Down Expand Up @@ -171,6 +172,9 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
.saturating_add(T::DbWeight::get().reads(4_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
fn set_max_unstake_ring() -> Weight {
Default::default()
}
/// Storage: `DarwiniaStaking::CollatorCount` (r:0 w:1)
/// Proof: `DarwiniaStaking::CollatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
fn set_collator_count() -> Weight {
Expand Down Expand Up @@ -293,6 +297,9 @@ impl WeightInfo for () {
.saturating_add(RocksDbWeight::get().reads(4_u64))
.saturating_add(RocksDbWeight::get().writes(1_u64))
}
fn set_max_unstake_ring() -> Weight {
Default::default()
}
/// Storage: `DarwiniaStaking::CollatorCount` (r:0 w:1)
/// Proof: `DarwiniaStaking::CollatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
fn set_collator_count() -> Weight {
Expand Down
20 changes: 14 additions & 6 deletions precompile/staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,16 +268,24 @@ impl ExtBuilder {
}

pub(crate) fn build(self) -> sp_io::TestExternalities {
let mut t = <frame_system::GenesisConfig<Runtime>>::default()
.build_storage()
.expect("Frame system builds valid default genesis config");
let mut storage =
<frame_system::GenesisConfig<Runtime>>::default().build_storage().unwrap();

pallet_balances::GenesisConfig::<Runtime> { balances: self.balances }
.assimilate_storage(&mut t)
.expect("Pallet balances storage can be assimilated");
.assimilate_storage(&mut storage)
.unwrap();
darwinia_staking::GenesisConfig::<Runtime> {
max_unstake_ring: 500,
collator_count: 1,
..Default::default()
}
.assimilate_storage(&mut storage)
.unwrap();

let mut ext = sp_io::TestExternalities::new(storage);

let mut ext = sp_io::TestExternalities::new(t);
ext.execute_with(|| System::set_block_number(1));

ext
}
}
3 changes: 3 additions & 0 deletions runtime/crab/src/weights/darwinia_staking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ impl<T: frame_system::Config> darwinia_staking::WeightInfo for WeightInfo<T> {
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(2))
}
fn set_max_unstake_ring() -> Weight {
Default::default()
}
/// Storage: `DarwiniaStaking::CollatorCount` (r:0 w:1)
/// Proof: `DarwiniaStaking::CollatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
fn set_collator_count() -> Weight {
Expand Down
3 changes: 3 additions & 0 deletions runtime/darwinia/src/weights/darwinia_staking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ impl<T: frame_system::Config> darwinia_staking::WeightInfo for WeightInfo<T> {
.saturating_add(T::DbWeight::get().reads(35))
.saturating_add(T::DbWeight::get().writes(2))
}
fn set_max_unstake_ring() -> Weight {
Default::default()
}
/// Storage: `DarwiniaStaking::CollatorCount` (r:0 w:1)
/// Proof: `DarwiniaStaking::CollatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
fn set_collator_count() -> Weight {
Expand Down
3 changes: 3 additions & 0 deletions runtime/pangolin/src/weights/darwinia_staking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ impl<T: frame_system::Config> darwinia_staking::WeightInfo for WeightInfo<T> {
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(2))
}
fn set_max_unstake_ring() -> Weight {
Default::default()
}
/// Storage: `DarwiniaStaking::CollatorCount` (r:0 w:1)
/// Proof: `DarwiniaStaking::CollatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
fn set_collator_count() -> Weight {
Expand Down

0 comments on commit 8ef837a

Please sign in to comment.