Skip to content

Commit

Permalink
Add force remove vesting (#1982)
Browse files Browse the repository at this point in the history
This PR exposes a `force_remove_vesting` through a ROOT call. 
See linked
[issue](#269)

---------

Co-authored-by: georgepisaltu <52418509+georgepisaltu@users.noreply.github.com>
Co-authored-by: command-bot <>
Co-authored-by: Dónal Murray <donal.murray@parity.io>
  • Loading branch information
3 people authored Nov 6, 2023
1 parent fb2dc6d commit 318e596
Show file tree
Hide file tree
Showing 6 changed files with 415 additions and 241 deletions.
29 changes: 21 additions & 8 deletions polkadot/runtime/rococo/src/weights/pallet_vesting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,16 +187,29 @@ impl<T: frame_system::Config> pallet_vesting::WeightInfo for WeightInfo<T> {
.saturating_add(T::DbWeight::get().reads(5))
.saturating_add(T::DbWeight::get().writes(4))
}
/// Storage: Vesting Vesting (r:1 w:1)
/// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen)
/// Storage: Balances Locks (r:1 w:1)
/// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen)
/// Storage: Balances Freezes (r:1 w:0)
/// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen)
/// Storage: System Account (r:1 w:1)
/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
/// Storage: `Vesting::Vesting` (r:1 w:1)
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
/// Storage: `Balances::Locks` (r:1 w:1)
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
/// Storage: `Balances::Freezes` (r:1 w:0)
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`)
/// Storage: `System::Account` (r:1 w:1)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
/// The range of component `l` is `[0, 49]`.
/// The range of component `s` is `[2, 28]`.
fn force_remove_vesting_schedule(l: u32, s: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `555 + l * (25 ±0) + s * (36 ±0)`
// Estimated: `4764`
// Minimum execution time: 41_497_000 picoseconds.
Weight::from_parts(38_763_834, 4764)
// Standard Error: 2_030
.saturating_add(Weight::from_parts(99_580, 0).saturating_mul(l.into()))
// Standard Error: 3_750
.saturating_add(Weight::from_parts(132_188, 0).saturating_mul(s.into()))
.saturating_add(T::DbWeight::get().reads(4_u64))
.saturating_add(T::DbWeight::get().writes(3_u64))
}
fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `378 + l * (25 ±0) + s * (36 ±0)`
Expand Down
24 changes: 24 additions & 0 deletions polkadot/runtime/westend/src/weights/pallet_vesting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,4 +238,28 @@ impl<T: frame_system::Config> pallet_vesting::WeightInfo for WeightInfo<T> {
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(3))
}

/// Storage: `Vesting::Vesting` (r:1 w:1)
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
/// Storage: `Balances::Locks` (r:1 w:1)
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
/// Storage: `Balances::Freezes` (r:1 w:0)
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`)
/// Storage: `System::Account` (r:1 w:1)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
/// The range of component `l` is `[0, 49]`.
/// The range of component `s` is `[2, 28]`.
fn force_remove_vesting_schedule(l: u32, s: u32) -> Weight {
// Proof Size summary in bytes:
// Measured: `555 + l * (25 ±0) + s * (36 ±0)`
// Estimated: `4764`
// Minimum execution time: 41_497_000 picoseconds.
Weight::from_parts(38_763_834, 4764)
// Standard Error: 2_030
.saturating_add(Weight::from_parts(99_580, 0).saturating_mul(l.into()))
// Standard Error: 3_750
.saturating_add(Weight::from_parts(132_188, 0).saturating_mul(s.into()))
.saturating_add(T::DbWeight::get().reads(4_u64))
.saturating_add(T::DbWeight::get().writes(3_u64))
}
}
27 changes: 27 additions & 0 deletions substrate/frame/vesting/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,33 @@ benchmarks! {
);
}

force_remove_vesting_schedule {
let l in 0 .. MaxLocksOf::<T>::get() - 1;
let s in 2 .. T::MAX_VESTING_SCHEDULES;

let source: T::AccountId = account("source", 0, SEED);
let source_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(source.clone());
T::Currency::make_free_balance_be(&source, BalanceOf::<T>::max_value());

let target: T::AccountId = account("target", 0, SEED);
let target_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(target.clone());
T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance());

// Give target existing locks.
add_locks::<T>(&target, l as u8);
let _ = add_vesting_schedules::<T>(target_lookup.clone(), s)?;

// The last vesting schedule.
let schedule_index = s - 1;
}: _(RawOrigin::Root, target_lookup, schedule_index)
verify {
assert_eq!(
Vesting::<T>::vesting(&target).unwrap().len(),
schedule_index as usize,
"Schedule count should reduce by 1"
);
}

impl_benchmark_test_suite!(
Vesting,
crate::mock::ExtBuilder::default().existential_deposit(256).build(),
Expand Down
30 changes: 30 additions & 0 deletions substrate/frame/vesting/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,36 @@ pub mod pallet {

Ok(())
}

/// Force remove a vesting schedule
///
/// The dispatch origin for this call must be _Root_.
///
/// - `target`: An account that has a vesting schedule
/// - `schedule_index`: The vesting schedule index that should be removed
#[pallet::call_index(5)]
#[pallet::weight(
T::WeightInfo::force_remove_vesting_schedule(MaxLocksOf::<T>::get(), T::MAX_VESTING_SCHEDULES)
)]
pub fn force_remove_vesting_schedule(
origin: OriginFor<T>,
target: <T::Lookup as StaticLookup>::Source,
schedule_index: u32,
) -> DispatchResultWithPostInfo {
ensure_root(origin)?;
let who = T::Lookup::lookup(target)?;

let schedules_count = Vesting::<T>::decode_len(&who).unwrap_or_default();
ensure!(schedule_index < schedules_count as u32, Error::<T>::InvalidScheduleParams);

Self::remove_vesting_schedule(&who, schedule_index)?;

Ok(Some(T::WeightInfo::force_remove_vesting_schedule(
MaxLocksOf::<T>::get(),
schedules_count as u32,
))
.into())
}
}
}

Expand Down
36 changes: 36 additions & 0 deletions substrate/frame/vesting/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1155,3 +1155,39 @@ fn vested_transfer_less_than_existential_deposit_fails() {
);
});
}

#[test]
fn remove_vesting_schedule() {
ExtBuilder::default().existential_deposit(ED).build().execute_with(|| {
assert_eq!(Balances::free_balance(&3), 256 * 30);
assert_eq!(Balances::free_balance(&4), 256 * 40);
// Account 4 should not have any vesting yet.
assert_eq!(Vesting::vesting(&4), None);
// Make the schedule for the new transfer.
let new_vesting_schedule = VestingInfo::new(
ED * 5,
(ED * 5) / 20, // Vesting over 20 blocks
10,
);
assert_ok!(Vesting::vested_transfer(Some(3).into(), 4, new_vesting_schedule));
// Now account 4 should have vesting.
assert_eq!(Vesting::vesting(&4).unwrap(), vec![new_vesting_schedule]);
// Account 4 has 5 * 256 locked.
assert_eq!(Vesting::vesting_balance(&4), Some(256 * 5));
// Verify only root can call.
assert_noop!(Vesting::force_remove_vesting_schedule(Some(4).into(), 4, 0), BadOrigin);
// Verify that root can remove the schedule.
assert_ok!(Vesting::force_remove_vesting_schedule(RawOrigin::Root.into(), 4, 0));
// Verify that last event is VestingCompleted.
System::assert_last_event(Event::VestingCompleted { account: 4 }.into());
// Appropriate storage is cleaned up.
assert!(!<VestingStorage<Test>>::contains_key(4));
// Check the vesting balance is zero.
assert_eq!(Vesting::vesting(&4), None);
// Verifies that trying to remove a schedule when it doesnt exist throws error.
assert_noop!(
Vesting::force_remove_vesting_schedule(RawOrigin::Root.into(), 4, 0),
Error::<Test>::InvalidScheduleParams
);
});
}
Loading

0 comments on commit 318e596

Please sign in to comment.