Lazy reaping (#4895)

* Squash and rebase from gav-lazy-reaping

* Bump version

* Bump runtime again

* Docs.

* Remove old functions

* Update frame/balances/src/lib.rs

Co-Authored-By: Shawn Tabrizi <shawntabrizi@gmail.com>

* Update frame/contracts/src/lib.rs

Co-Authored-By: Shawn Tabrizi <shawntabrizi@gmail.com>

* Warnings

* Bump runtime version

* Update frame/democracy/src/lib.rs

Co-Authored-By: Shawn Tabrizi <shawntabrizi@gmail.com>

* Update frame/system/src/lib.rs

* Clean up OnReapAccount

* Use frame_support debug

* Bump spec

* Renames and fix

* Fix

* Fix rename

* Fix

* Increase time for test

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
Co-authored-by: Benjamin Kampmann <ben.kampmann@googlemail.com>
This commit is contained in:
Gavin Wood
2020-02-24 14:04:42 -03:00
committed by GitHub
parent c412c6230e
commit afa5861f3b
62 changed files with 604 additions and 287 deletions
+38 -19
View File
@@ -159,9 +159,8 @@ use codec::{Encode, Decode};
use frame_support::{
decl_module, decl_event, decl_storage, decl_error, ensure,
Parameter, RuntimeDebug,
weights::{GetDispatchInfo, SimpleDispatchInfo, FunctionOf},
traits::{Currency, ReservableCurrency, Get, OnReapAccount, BalanceStatus},
Parameter, RuntimeDebug, weights::{GetDispatchInfo, SimpleDispatchInfo, FunctionOf},
traits::{Currency, ReservableCurrency, Get, BalanceStatus},
};
use frame_system::{self as system, ensure_signed, ensure_root};
@@ -241,6 +240,7 @@ decl_storage! {
pub Recoverable get(fn recovery_config):
map hasher(blake2_256) T::AccountId
=> Option<RecoveryConfig<T::BlockNumber, BalanceOf<T>, T::AccountId>>;
/// Active recovery attempts.
///
/// First account is the account to be recovered, and the second account
@@ -248,10 +248,11 @@ decl_storage! {
pub ActiveRecoveries get(fn active_recovery):
double_map hasher(twox_64_concat) T::AccountId, hasher(twox_64_concat) T::AccountId =>
Option<ActiveRecovery<T::BlockNumber, BalanceOf<T>, T::AccountId>>;
/// The final list of recovered accounts.
/// The list of allowed proxy accounts.
///
/// Map from the recovered account to the user who can access it.
pub Recovered get(fn recovered_account):
/// Map from the user who can access it to the recovered account.
pub Proxy get(fn proxy):
map hasher(blake2_256) T::AccountId => Option<T::AccountId>;
}
}
@@ -308,6 +309,8 @@ decl_error! {
StillActive,
/// There was an overflow in a calculation
Overflow,
/// This account is already set up for recovery
AlreadyProxy,
}
}
@@ -332,7 +335,7 @@ decl_module! {
/// - One storage lookup to check account is recovered by `who`. O(1)
/// # </weight>
#[weight = FunctionOf(
|args: (&T::AccountId, &Box<<T as Trait>::Call>)| args.1.get_dispatch_info().weight + 10_000,
|args: (&T::AccountId, &Box<<T as Trait>::Call>)| args.1.get_dispatch_info().weight + 10_000,
|args: (&T::AccountId, &Box<<T as Trait>::Call>)| args.1.get_dispatch_info().class,
true
)]
@@ -342,7 +345,8 @@ decl_module! {
) -> DispatchResult {
let who = ensure_signed(origin)?;
// Check `who` is allowed to make a call on behalf of `account`
ensure!(Self::recovered_account(&account) == Some(who), Error::<T>::NotAllowed);
let target = Self::proxy(&who).ok_or(Error::<T>::NotAllowed)?;
ensure!(&target == &account, Error::<T>::NotAllowed);
call.dispatch(frame_system::RawOrigin::Signed(account).into())
}
@@ -363,7 +367,7 @@ decl_module! {
fn set_recovered(origin, lost: T::AccountId, rescuer: T::AccountId) {
ensure_root(origin)?;
// Create the recovery storage item.
<Recovered<T>>::insert(&lost, &rescuer);
<Proxy<T>>::insert(&rescuer, &lost);
Self::deposit_event(RawEvent::AccountRecovered(lost, rescuer));
}
@@ -428,6 +432,7 @@ decl_module! {
};
// Create the recovery configuration storage item
<Recoverable<T>>::insert(&who, recovery_config);
Self::deposit_event(RawEvent::RecoveryCreated(who));
}
@@ -545,6 +550,7 @@ decl_module! {
let recovery_config = Self::recovery_config(&account).ok_or(Error::<T>::NotRecoverable)?;
// Get the active recovery process for the rescuer
let active_recovery = Self::active_recovery(&account, &who).ok_or(Error::<T>::NotStarted)?;
ensure!(!Proxy::<T>::contains_key(&who), Error::<T>::AlreadyProxy);
// Make sure the delay period has passed
let current_block_number = <system::Module<T>>::block_number();
let recoverable_block_number = active_recovery.created
@@ -557,7 +563,8 @@ decl_module! {
Error::<T>::Threshold
);
// Create the recovery storage item
<Recovered<T>>::insert(&account, &who);
Proxy::<T>::insert(&who, &account);
system::Module::<T>::inc_ref(&who);
Self::deposit_event(RawEvent::AccountRecovered(account, who));
}
@@ -592,7 +599,7 @@ decl_module! {
Self::deposit_event(RawEvent::RecoveryClosed(who, rescuer));
}
/// Remove the recovery process for your account.
/// Remove the recovery process for your account. Recovered accounts are still accessible.
///
/// NOTE: The user must make sure to call `close_recovery` on all active
/// recovery attempts before calling this function else it will fail.
@@ -621,10 +628,30 @@ decl_module! {
ensure!(active_recoveries.next().is_none(), Error::<T>::StillActive);
// Take the recovery configuration for this account.
let recovery_config = <Recoverable<T>>::take(&who).ok_or(Error::<T>::NotRecoverable)?;
// Unreserve the initial deposit for the recovery configuration.
T::Currency::unreserve(&who, recovery_config.deposit);
Self::deposit_event(RawEvent::RecoveryRemoved(who));
}
/// Cancel the ability to use `as_recovered` for `account`.
///
/// The dispatch origin for this call must be _Signed_ and registered to
/// be able to make calls on behalf of the recovered account.
///
/// Parameters:
/// - `account`: The recovered account you are able to call on-behalf-of.
///
/// # <weight>
/// - One storage mutation to check account is recovered by `who`. O(1)
/// # </weight>
fn cancel_recovered(origin, account: T::AccountId) {
let who = ensure_signed(origin)?;
// Check `who` is allowed to make a call on behalf of `account`
ensure!(Self::proxy(&who) == Some(account), Error::<T>::NotAllowed);
Proxy::<T>::remove(&who);
system::Module::<T>::dec_ref(&who);
}
}
}
@@ -639,11 +666,3 @@ impl<T: Trait> Module<T> {
friends.binary_search(&friend).is_ok()
}
}
impl<T: Trait> OnReapAccount<T::AccountId> for Module<T> {
/// Remove any existing access another account might have when the account is reaped.
/// This removes the final storage item managed by this module for any given account.
fn on_reap_account(who: &T::AccountId) {
<Recovered<T>>::remove(who);
}
}
+1 -1
View File
@@ -80,7 +80,7 @@ impl frame_system::Trait for Test {
type ModuleToIndex = ();
type AccountData = pallet_balances::AccountData<u128>;
type OnNewAccount = ();
type OnReapAccount = (Balances, Recovery);
type OnKilledAccount = ();
}
parameter_types! {
+7 -4
View File
@@ -31,7 +31,7 @@ use frame_support::{
fn basic_setup_works() {
new_test_ext().execute_with(|| {
// Nothing in storage to start
assert_eq!(Recovery::recovered_account(&1), None);
assert_eq!(Recovery::proxy(&2), None);
assert_eq!(Recovery::active_recovery(&1, &2), None);
assert_eq!(Recovery::recovery_config(&1), None);
// Everyone should have starting balance of 100
@@ -91,10 +91,13 @@ fn recovery_life_cycle_works() {
// All funds have been fully recovered!
assert_eq!(Balances::free_balance(1), 200);
assert_eq!(Balances::free_balance(5), 0);
// Remove the proxy link.
assert_ok!(Recovery::cancel_recovered(Origin::signed(1), 5));
// All storage items are removed from the module
assert!(!<ActiveRecoveries<Test>>::contains_key(&5, &1));
assert!(!<Recoverable<Test>>::contains_key(&5));
assert!(!<Recovered<Test>>::contains_key(&5));
assert!(!<Proxy<Test>>::contains_key(&1));
});
}
@@ -335,7 +338,7 @@ fn claim_recovery_works() {
// Account can be recovered.
assert_ok!(Recovery::claim_recovery(Origin::signed(1), 5));
// Recovered storage item is correctly created
assert_eq!(<Recovered<Test>>::get(&5), Some(1));
assert_eq!(<Proxy<Test>>::get(&1), Some(5));
// Account could be re-recovered in the case that the recoverer account also gets lost.
assert_ok!(Recovery::initiate_recovery(Origin::signed(4), 5));
assert_ok!(Recovery::vouch_recovery(Origin::signed(2), 5, 4));
@@ -347,7 +350,7 @@ fn claim_recovery_works() {
// Account is re-recovered.
assert_ok!(Recovery::claim_recovery(Origin::signed(4), 5));
// Recovered storage item is correctly updated
assert_eq!(<Recovered<Test>>::get(&5), Some(4));
assert_eq!(<Proxy<Test>>::get(&4), Some(5));
});
}