From eb622d4c010f9faeaf2a3eb3f1428fb069bf12b3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Jan 2020 17:26:36 +0100 Subject: [PATCH 01/29] Initially scoping out of the problem --- frame/balances/src/lib.rs | 11 +++++++++++ frame/democracy/src/lib.rs | 3 +++ 2 files changed, 14 insertions(+) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index b488b96701cf1..2487a7c2e45d5 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -349,6 +349,8 @@ decl_storage! { config.balances.iter().fold(Zero::zero(), |acc: T::Balance, &(_, n)| acc + n) }): T::Balance; + // TODO: should be in a different pallet and just use the locking system. + /// Information regarding the vesting of a given account. pub Vesting get(fn vesting) build(|config: &GenesisConfig| { // Generate initial vesting configuration @@ -376,6 +378,14 @@ decl_storage! { }).collect::>() }): map T::AccountId => Option>; + // TODO: amalgamate the next two into a single item, and also include: + // - fees-locked (min balance to be kept regarding payment of fees - paying a + // fee may not result in the balance being reduced to below this amount) + // - tips-locked (min balance to be kept when paying tx tip) + // - transfer-locked (min balance to be kept when transferring) + // - reserve-locked (min balance to be kept when reserving) + // consider combining the last three and only have fees and non-fees. + /// The 'free' balance of a given account. /// /// This is the only balance that matters in terms of most operations on tokens. It @@ -405,6 +415,7 @@ decl_storage! { pub ReservedBalance get(fn reserved_balance): map T::AccountId => T::Balance; /// Any liquidity locks on some account balances. + /// NOTE: Should only be accessed when setting, changing and freeing a lock. pub Locks get(fn locks): map T::AccountId => Vec>; } add_extra_genesis { diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 354e93cc292ee..6022bd3309b30 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -712,6 +712,9 @@ decl_module! { let (_, conviction) = >::take(&who); // Indefinite lock is reduced to the maximum voting lock that could be possible. let now = >::block_number(); + // TODO: refactor this so that `locked_until` is stored in this pallet and there's + // an extra step (call) to be made explicitly by the user to unlock the funds after + // `locked_until`. let locked_until = now + T::EnactmentPeriod::get() * conviction.lock_periods().into(); T::Currency::set_lock( DEMOCRACY_ID, From d64eb64feb7ec828987002f9d6876659d26ff1c5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Jan 2020 17:45:25 +0100 Subject: [PATCH 02/29] Remove need for exiry in balance locks. --- frame/democracy/src/lib.rs | 64 ++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 6022bd3309b30..b9902ae67d914 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -299,6 +299,10 @@ decl_storage! { /// Get the account (and lock periods) to which another account is delegating vote. pub Delegations get(fn delegations): linked_map T::AccountId => (T::AccountId, Conviction); + /// Accounts for which there are locks in action which may be removed at some point in the + /// future. The value is the block number at which the lock expires and may be removed. + pub Locks get(locks): map T::AccountId => Option; + /// True if the last referendum tabled was submitted externally. False if it was a public /// proposal. pub LastTabledWasExternal: bool; @@ -357,6 +361,8 @@ decl_event! { PreimageMissing(Hash, ReferendumIndex), /// A registered preimage was removed and the deposit collected by the reaper (last item). PreimageReaped(Hash, AccountId, Balance, AccountId), + /// An account has been unlocked successfully. + Unlocked(AccountId), } } @@ -406,6 +412,10 @@ decl_error! { PreimageInvalid, /// No proposals waiting NoneWaiting, + /// The target account does not have a lock. + NotLocked, + /// The lock on the account to be unlocked has not yet expired. + NotExpired, } } @@ -697,6 +707,7 @@ decl_module! { T::BlockNumber::max_value(), WithdrawReason::Transfer.into() ); + Locks::::remove(&who); Self::deposit_event(RawEvent::Delegated(who, to)); } @@ -712,16 +723,14 @@ decl_module! { let (_, conviction) = >::take(&who); // Indefinite lock is reduced to the maximum voting lock that could be possible. let now = >::block_number(); - // TODO: refactor this so that `locked_until` is stored in this pallet and there's - // an extra step (call) to be made explicitly by the user to unlock the funds after - // `locked_until`. let locked_until = now + T::EnactmentPeriod::get() * conviction.lock_periods().into(); + Locks::::insert(&who, locked_until); T::Currency::set_lock( DEMOCRACY_ID, &who, Bounded::max_value(), - locked_until, - WithdrawReason::Transfer.into() + T::BlockNumber::max_value(), + WithdrawReason::Transfer.into(), ); Self::deposit_event(RawEvent::Undelegated(who)); } @@ -792,6 +801,18 @@ decl_module! { >::remove(&proposal_hash); Self::deposit_event(RawEvent::PreimageReaped(proposal_hash, old, deposit, who)); } + + #[weight = SimpleDispatchInfo::FixedNormal(10_000)] + fn unlock(origin, target: T::AccountId) { + ensure_signed(origin)?; + + let expiry = Locks::::get(&target).ok_or(Error::::NotLocked)?; + ensure!(expiry <= system::Module::::block_number(), Error::::NotExpired); + + T::Currency::remove_lock(DEMOCRACY_ID, &target); + Locks::::remove(&target); + Self::deposit_event(RawEvent::Unlocked(target)); + } } } @@ -1077,14 +1098,16 @@ impl Module { // now plus: the base lock period multiplied by the number of periods this voter // offered to lock should they win... let locked_until = now + T::EnactmentPeriod::get() * conviction.lock_periods().into(); + Locks::::insert(&a, locked_until); // ...extend their bondage until at least then. T::Currency::extend_lock( DEMOCRACY_ID, &a, Bounded::max_value(), - locked_until, + T::BlockNumber::max_value(), WithdrawReason::Transfer.into() ); + } Self::clear_referendum(index); @@ -2395,24 +2418,47 @@ mod tests { assert_eq!(Balances::locks(2), vec![BalanceLock { id: DEMOCRACY_ID, amount: u64::max_value(), - until: 18, + until: u64::max_value(), reasons: WithdrawReason::Transfer.into() }]); + assert_eq!(Democracy::locks(2), Some(18)); assert_eq!(Balances::locks(3), vec![BalanceLock { id: DEMOCRACY_ID, amount: u64::max_value(), - until: 10, + until: u64::max_value(), reasons: WithdrawReason::Transfer.into() }]); + assert_eq!(Democracy::locks(3), Some(10)); assert_eq!(Balances::locks(4), vec![BalanceLock { id: DEMOCRACY_ID, amount: u64::max_value(), - until: 6, + until: u64::max_value(), reasons: WithdrawReason::Transfer.into() }]); + assert_eq!(Democracy::locks(4), Some(6)); assert_eq!(Balances::locks(5), vec![]); assert_eq!(Balances::free_balance(&42), 2); + + assert_noop!(Democracy::unlock(Origin::signed(1), 1), Error::::NotLocked); + + fast_forward_to(5); + assert_noop!(Democracy::unlock(Origin::signed(1), 4), Error::::NotExpired); + fast_forward_to(6); + assert_ok!(Democracy::unlock(Origin::signed(1), 4)); + assert_noop!(Democracy::unlock(Origin::signed(1), 4), Error::::NotLocked); + + fast_forward_to(9); + assert_noop!(Democracy::unlock(Origin::signed(1), 3), Error::::NotExpired); + fast_forward_to(10); + assert_ok!(Democracy::unlock(Origin::signed(1), 3)); + assert_noop!(Democracy::unlock(Origin::signed(1), 3), Error::::NotLocked); + + fast_forward_to(17); + assert_noop!(Democracy::unlock(Origin::signed(1), 2), Error::::NotExpired); + fast_forward_to(18); + assert_ok!(Democracy::unlock(Origin::signed(1), 2)); + assert_noop!(Democracy::unlock(Origin::signed(1), 2), Error::::NotLocked); }); } From 1d7d8810f9c19d06b7c5c93d57f4fe19ec7ae297 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Jan 2020 17:58:46 +0100 Subject: [PATCH 03/29] Remove expiry from locks. --- frame/balances/src/lib.rs | 26 ++++------------- frame/balances/src/tests.rs | 45 ++++++++++++++--------------- frame/democracy/src/lib.rs | 3 -- frame/elections-phragmen/src/lib.rs | 1 - frame/elections/src/lib.rs | 1 - frame/executive/src/lib.rs | 1 - frame/generic-asset/src/lib.rs | 29 ++++--------------- frame/staking/src/lib.rs | 1 - frame/support/src/traits.rs | 3 -- 9 files changed, 33 insertions(+), 77 deletions(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 2487a7c2e45d5..028dfd2c2dfd0 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -141,7 +141,6 @@ //! STAKING_ID, //! &ledger.stash, //! ledger.total, -//! T::BlockNumber::max_value(), //! WithdrawReasons::all() //! ); //! // >::insert(controller, ledger); // Commented out as we don't have access to Staking's storage here. @@ -338,7 +337,6 @@ impl Ves pub struct BalanceLock { pub id: LockIdentifier, pub amount: Balance, - pub until: BlockNumber, pub reasons: WithdrawReasons, } @@ -1255,19 +1253,15 @@ where id: LockIdentifier, who: &T::AccountId, amount: T::Balance, - until: T::BlockNumber, reasons: WithdrawReasons, ) { if amount.is_zero() { return } - let now = >::block_number(); - let mut new_lock = Some(BalanceLock { id, amount, until, reasons }); + let mut new_lock = Some(BalanceLock { id, amount, reasons }); let mut locks = Self::locks(who).into_iter().filter_map(|l| if l.id == id { new_lock.take() - } else if l.until > now { - Some(l) } else { - None + Some(l) }).collect::>(); if let Some(lock) = new_lock { locks.push(lock) @@ -1279,10 +1273,8 @@ where id: LockIdentifier, who: &T::AccountId, amount: T::Balance, - until: T::BlockNumber, reasons: WithdrawReasons, ) { - let now = >::block_number(); let mut new_lock = Some(BalanceLock { id, amount, until, reasons }); let mut locks = Self::locks(who).into_iter().filter_map(|l| if l.id == id { @@ -1290,14 +1282,11 @@ where BalanceLock { id: l.id, amount: l.amount.max(nl.amount), - until: l.until.max(nl.until), reasons: l.reasons | nl.reasons, } }) - } else if l.until > now { - Some(l) } else { - None + Some(l) }).collect::>(); if let Some(lock) = new_lock { locks.push(lock) @@ -1309,13 +1298,8 @@ where id: LockIdentifier, who: &T::AccountId, ) { - let now = >::block_number(); - let locks = Self::locks(who).into_iter().filter_map(|l| - if l.until > now && l.id != id { - Some(l) - } else { - None - }).collect::>(); + let mut locks = Self::locks(who); + locks.retain(|l| l.id != id); >::insert(who, locks); } } diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index 175e87aea4b4c..c6c129e5583bf 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -35,7 +35,7 @@ const ID_3: LockIdentifier = *b"3 "; fn basic_locking_should_work() { ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { assert_eq!(Balances::free_balance(&1), 10); - Balances::set_lock(ID_1, &1, 9, u64::max_value(), WithdrawReasons::all()); + Balances::set_lock(ID_1, &1, 9, WithdrawReasons::all()); assert_noop!( >::transfer(&1, &2, 5, AllowDeath), Error::::LiquidityRestrictions @@ -46,7 +46,7 @@ fn basic_locking_should_work() { #[test] fn partial_locking_should_work() { ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { - Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all()); + Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all()); assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); }); } @@ -54,7 +54,7 @@ fn partial_locking_should_work() { #[test] fn lock_removal_should_work() { ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { - Balances::set_lock(ID_1, &1, u64::max_value(), u64::max_value(), WithdrawReasons::all()); + Balances::set_lock(ID_1, &1, u64::max_value(), WithdrawReasons::all()); Balances::remove_lock(ID_1, &1); assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); }); @@ -63,8 +63,8 @@ fn lock_removal_should_work() { #[test] fn lock_replacement_should_work() { ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { - Balances::set_lock(ID_1, &1, u64::max_value(), u64::max_value(), WithdrawReasons::all()); - Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all()); + Balances::set_lock(ID_1, &1, u64::max_value(), WithdrawReasons::all()); + Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all()); assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); }); } @@ -72,8 +72,8 @@ fn lock_replacement_should_work() { #[test] fn double_locking_should_work() { ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { - Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all()); - Balances::set_lock(ID_2, &1, 5, u64::max_value(), WithdrawReasons::all()); + Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all()); + Balances::set_lock(ID_2, &1, 5, WithdrawReasons::all()); assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); }); } @@ -81,9 +81,8 @@ fn double_locking_should_work() { #[test] fn combination_locking_should_work() { ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { - Balances::set_lock(ID_1, &1, u64::max_value(), 0, WithdrawReasons::none()); - Balances::set_lock(ID_2, &1, 0, u64::max_value(), WithdrawReasons::none()); - Balances::set_lock(ID_3, &1, 0, 0, WithdrawReasons::all()); + Balances::set_lock(ID_1, &1, u64::max_value(), WithdrawReasons::none()); + Balances::set_lock(ID_2, &1, 0, WithdrawReasons::all()); assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); }); } @@ -91,17 +90,17 @@ fn combination_locking_should_work() { #[test] fn lock_value_extension_should_work() { ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { - Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all()); + Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all()); assert_noop!( >::transfer(&1, &2, 6, AllowDeath), Error::::LiquidityRestrictions ); - Balances::extend_lock(ID_1, &1, 2, u64::max_value(), WithdrawReasons::all()); + Balances::extend_lock(ID_1, &1, 2, WithdrawReasons::all()); assert_noop!( >::transfer(&1, &2, 6, AllowDeath), Error::::LiquidityRestrictions ); - Balances::extend_lock(ID_1, &1, 8, u64::max_value(), WithdrawReasons::all()); + Balances::extend_lock(ID_1, &1, 8, WithdrawReasons::all()); assert_noop!( >::transfer(&1, &2, 3, AllowDeath), Error::::LiquidityRestrictions @@ -116,7 +115,7 @@ fn lock_reasons_should_work() { .monied(true) .build() .execute_with(|| { - Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::Transfer.into()); + Balances::set_lock(ID_1, &1, 10, WithdrawReason::Transfer.into()); assert_noop!( >::transfer(&1, &2, 1, AllowDeath), Error::::LiquidityRestrictions @@ -131,7 +130,7 @@ fn lock_reasons_should_work() { 0, ).is_ok()); - Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::Reserve.into()); + Balances::set_lock(ID_1, &1, 10, WithdrawReason::Reserve.into()); assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); assert_noop!( >::reserve(&1, 1), @@ -145,7 +144,7 @@ fn lock_reasons_should_work() { 0, ).is_ok()); - Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::TransactionPayment.into()); + Balances::set_lock(ID_1, &1, 10, WithdrawReason::TransactionPayment.into()); assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); assert_ok!(>::reserve(&1, 1)); assert!( as SignedExtension>::pre_dispatch( @@ -161,7 +160,7 @@ fn lock_reasons_should_work() { #[test] fn lock_block_number_should_work() { ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { - Balances::set_lock(ID_1, &1, 10, 2, WithdrawReasons::all()); + Balances::set_lock(ID_1, &1, 10, WithdrawReasons::all()); assert_noop!( >::transfer(&1, &2, 1, AllowDeath), Error::::LiquidityRestrictions @@ -175,18 +174,18 @@ fn lock_block_number_should_work() { #[test] fn lock_block_number_extension_should_work() { ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { - Balances::set_lock(ID_1, &1, 10, 2, WithdrawReasons::all()); + Balances::set_lock(ID_1, &1, 10, WithdrawReasons::all()); assert_noop!( >::transfer(&1, &2, 6, AllowDeath), Error::::LiquidityRestrictions ); - Balances::extend_lock(ID_1, &1, 10, 1, WithdrawReasons::all()); + Balances::extend_lock(ID_1, &1, 10, WithdrawReasons::all()); assert_noop!( >::transfer(&1, &2, 6, AllowDeath), Error::::LiquidityRestrictions ); System::set_block_number(2); - Balances::extend_lock(ID_1, &1, 10, 8, WithdrawReasons::all()); + Balances::extend_lock(ID_1, &1, 10, WithdrawReasons::all()); assert_noop!( >::transfer(&1, &2, 3, AllowDeath), Error::::LiquidityRestrictions @@ -197,17 +196,17 @@ fn lock_block_number_extension_should_work() { #[test] fn lock_reasons_extension_should_work() { ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { - Balances::set_lock(ID_1, &1, 10, 10, WithdrawReason::Transfer.into()); + Balances::set_lock(ID_1, &1, 10, WithdrawReason::Transfer.into()); assert_noop!( >::transfer(&1, &2, 6, AllowDeath), Error::::LiquidityRestrictions ); - Balances::extend_lock(ID_1, &1, 10, 10, WithdrawReasons::none()); + Balances::extend_lock(ID_1, &1, 10, WithdrawReasons::none()); assert_noop!( >::transfer(&1, &2, 6, AllowDeath), Error::::LiquidityRestrictions ); - Balances::extend_lock(ID_1, &1, 10, 10, WithdrawReason::Reserve.into()); + Balances::extend_lock(ID_1, &1, 10, WithdrawReason::Reserve.into()); assert_noop!( >::transfer(&1, &2, 6, AllowDeath), Error::::LiquidityRestrictions diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index b9902ae67d914..d10162246c3d5 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -704,7 +704,6 @@ decl_module! { DEMOCRACY_ID, &who, Bounded::max_value(), - T::BlockNumber::max_value(), WithdrawReason::Transfer.into() ); Locks::::remove(&who); @@ -729,7 +728,6 @@ decl_module! { DEMOCRACY_ID, &who, Bounded::max_value(), - T::BlockNumber::max_value(), WithdrawReason::Transfer.into(), ); Self::deposit_event(RawEvent::Undelegated(who)); @@ -1104,7 +1102,6 @@ impl Module { DEMOCRACY_ID, &a, Bounded::max_value(), - T::BlockNumber::max_value(), WithdrawReason::Transfer.into() ); diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 1d9573cbbf320..c5dc5689d9011 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -260,7 +260,6 @@ decl_module! { MODULE_ID, &who, locked_balance, - T::BlockNumber::max_value(), WithdrawReasons::except(WithdrawReason::TransactionPayment), ); >::insert(&who, locked_balance); diff --git a/frame/elections/src/lib.rs b/frame/elections/src/lib.rs index e722c4db8050e..9cc650591bba1 100644 --- a/frame/elections/src/lib.rs +++ b/frame/elections/src/lib.rs @@ -891,7 +891,6 @@ impl Module { MODULE_ID, &who, locked_balance, - T::BlockNumber::max_value(), WithdrawReasons::all(), ); diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 0507946ef565b..0c3c2fe46ba82 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -712,7 +712,6 @@ mod tests { id, &1, 110, - Bounded::max_value(), lock, ); let xt = sp_runtime::testing::TestXt( diff --git a/frame/generic-asset/src/lib.rs b/frame/generic-asset/src/lib.rs index 3b509a683d705..f13ea971312c0 100644 --- a/frame/generic-asset/src/lib.rs +++ b/frame/generic-asset/src/lib.rs @@ -444,7 +444,6 @@ decl_module! { pub struct BalanceLock { pub id: LockIdentifier, pub amount: Balance, - pub until: BlockNumber, pub reasons: WithdrawReasons, } @@ -835,14 +834,11 @@ impl Module { id: LockIdentifier, who: &T::AccountId, amount: T::Balance, - until: T::BlockNumber, reasons: WithdrawReasons, ) { - let now = >::block_number(); let mut new_lock = Some(BalanceLock { id, amount, - until, reasons, }); let mut locks = >::locks(who) @@ -850,10 +846,8 @@ impl Module { .filter_map(|l| { if l.id == id { new_lock.take() - } else if l.until > now { - Some(l) } else { - None + Some(l) } }) .collect::>(); @@ -867,14 +861,11 @@ impl Module { id: LockIdentifier, who: &T::AccountId, amount: T::Balance, - until: T::BlockNumber, reasons: WithdrawReasons, ) { - let now = >::block_number(); let mut new_lock = Some(BalanceLock { id, amount, - until, reasons, }); let mut locks = >::locks(who) @@ -884,13 +875,10 @@ impl Module { new_lock.take().map(|nl| BalanceLock { id: l.id, amount: l.amount.max(nl.amount), - until: l.until.max(nl.until), reasons: l.reasons | nl.reasons, }) - } else if l.until > now { - Some(l) } else { - None + Some(l) } }) .collect::>(); @@ -901,11 +889,8 @@ impl Module { } fn remove_lock(id: LockIdentifier, who: &T::AccountId) { - let now = >::block_number(); - let locks = >::locks(who) - .into_iter() - .filter_map(|l| if l.until > now && l.id != id { Some(l) } else { None }) - .collect::>(); + let mut locks = >::locks(who) + locks.retain(|l| l.id != id); >::insert(who, locks); } } @@ -1349,20 +1334,18 @@ where id: LockIdentifier, who: &T::AccountId, amount: T::Balance, - until: T::BlockNumber, reasons: WithdrawReasons, ) { - >::set_lock(id, who, amount, until, reasons) + >::set_lock(id, who, amount, reasons) } fn extend_lock( id: LockIdentifier, who: &T::AccountId, amount: T::Balance, - until: T::BlockNumber, reasons: WithdrawReasons, ) { - >::extend_lock(id, who, amount, until, reasons) + >::extend_lock(id, who, amount, reasons) } fn remove_lock(id: LockIdentifier, who: &T::AccountId) { diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 326a01599034c..b26e4f18adb23 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -1279,7 +1279,6 @@ impl Module { STAKING_ID, &ledger.stash, ledger.total, - T::BlockNumber::max_value(), WithdrawReasons::all(), ); >::insert(controller, ledger); diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index cb2228392454f..7cc8def9e41a0 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -581,7 +581,6 @@ pub trait LockableCurrency: Currency { id: LockIdentifier, who: &AccountId, amount: Self::Balance, - until: Self::Moment, reasons: WithdrawReasons, ); @@ -592,13 +591,11 @@ pub trait LockableCurrency: Currency { /// applies the most severe constraints of the two, while `set_lock` replaces the lock /// with the new parameters. As in, `extend_lock` will set: /// - maximum `amount` - /// - farthest duration (`until`) /// - bitwise mask of all `reasons` fn extend_lock( id: LockIdentifier, who: &AccountId, amount: Self::Balance, - until: Self::Moment, reasons: WithdrawReasons, ); From 726de0e148155f3414f9b2489a81124244957712 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Jan 2020 20:18:31 +0100 Subject: [PATCH 04/29] Remove supefluous balance test --- frame/balances/src/lib.rs | 15 ++++----------- frame/balances/src/tests.rs | 15 --------------- frame/generic-asset/src/lib.rs | 4 ++-- 3 files changed, 6 insertions(+), 28 deletions(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 028dfd2c2dfd0..17d5d637b3ce8 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -334,7 +334,7 @@ impl Ves } #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] -pub struct BalanceLock { +pub struct BalanceLock { pub id: LockIdentifier, pub amount: Balance, pub reasons: WithdrawReasons, @@ -414,7 +414,7 @@ decl_storage! { /// Any liquidity locks on some account balances. /// NOTE: Should only be accessed when setting, changing and freeing a lock. - pub Locks get(fn locks): map T::AccountId => Vec>; + pub Locks get(fn locks): map T::AccountId => Vec>; } add_extra_genesis { config(balances): Vec<(T::AccountId, T::Balance)>; @@ -965,14 +965,7 @@ where return Ok(()) } - let now = >::block_number(); - if locks.into_iter() - .all(|l| - now >= l.until - || new_balance >= l.amount - || !l.reasons.intersects(reasons) - ) - { + if locks.into_iter().all(|l| new_balance >= l.amount || !l.reasons.intersects(reasons)) { Ok(()) } else { Err(Error::::LiquidityRestrictions.into()) @@ -1275,7 +1268,7 @@ where amount: T::Balance, reasons: WithdrawReasons, ) { - let mut new_lock = Some(BalanceLock { id, amount, until, reasons }); + let mut new_lock = Some(BalanceLock { id, amount, reasons }); let mut locks = Self::locks(who).into_iter().filter_map(|l| if l.id == id { new_lock.take().map(|nl| { diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index c6c129e5583bf..111160950f4b0 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -29,7 +29,6 @@ use frame_system::RawOrigin; const ID_1: LockIdentifier = *b"1 "; const ID_2: LockIdentifier = *b"2 "; -const ID_3: LockIdentifier = *b"3 "; #[test] fn basic_locking_should_work() { @@ -157,20 +156,6 @@ fn lock_reasons_should_work() { }); } -#[test] -fn lock_block_number_should_work() { - ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { - Balances::set_lock(ID_1, &1, 10, WithdrawReasons::all()); - assert_noop!( - >::transfer(&1, &2, 1, AllowDeath), - Error::::LiquidityRestrictions - ); - - System::set_block_number(2); - assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); - }); -} - #[test] fn lock_block_number_extension_should_work() { ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { diff --git a/frame/generic-asset/src/lib.rs b/frame/generic-asset/src/lib.rs index f13ea971312c0..4f602249e57ac 100644 --- a/frame/generic-asset/src/lib.rs +++ b/frame/generic-asset/src/lib.rs @@ -441,7 +441,7 @@ decl_module! { } #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] -pub struct BalanceLock { +pub struct BalanceLock { pub id: LockIdentifier, pub amount: Balance, pub reasons: WithdrawReasons, @@ -468,7 +468,7 @@ decl_storage! { pub Permissions get(fn get_permission): map T::AssetId => PermissionVersions; /// Any liquidity locks on some account balances. - pub Locks get(fn locks): map T::AccountId => Vec>; + pub Locks get(fn locks): map T::AccountId => Vec>; /// The identity of the asset which is the one that is designated for the chain's staking system. pub StakingAssetId get(fn staking_asset_id) config(): T::AssetId; From 73ad7ec0a39be5fb047fd5644b51336a06b6416a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 20 Jan 2020 19:53:26 +0100 Subject: [PATCH 05/29] Amalgamate pieces of balance module --- bin/node-template/runtime/src/lib.rs | 2 - bin/node/runtime/src/lib.rs | 3 - frame/balances/src/lib.rs | 422 ++++++++++++++++++--------- frame/balances/src/mock.rs | 17 +- frame/balances/src/tests.rs | 59 ++-- frame/contracts/src/lib.rs | 6 - frame/contracts/src/tests.rs | 2 - frame/democracy/src/lib.rs | 2 - frame/elections-phragmen/src/lib.rs | 4 +- frame/elections/src/lib.rs | 2 +- frame/elections/src/mock.rs | 2 - frame/example/src/lib.rs | 2 - frame/executive/src/lib.rs | 2 - frame/generic-asset/src/lib.rs | 6 +- frame/identity/src/lib.rs | 2 - frame/nicks/src/lib.rs | 2 - frame/recovery/src/mock.rs | 2 - frame/scored-pool/src/mock.rs | 2 - frame/society/src/mock.rs | 2 - frame/staking/src/mock.rs | 2 - frame/support/src/traits.rs | 6 +- frame/transaction-payment/src/lib.rs | 4 +- frame/treasury/src/lib.rs | 2 - frame/utility/src/lib.rs | 2 - 24 files changed, 325 insertions(+), 232 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 4416cbf13ee00..cee3111adc0e5 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -196,7 +196,6 @@ impl timestamp::Trait for Runtime { parameter_types! { pub const ExistentialDeposit: u128 = 500; - pub const TransferFee: u128 = 0; pub const CreationFee: u128 = 0; } @@ -214,7 +213,6 @@ impl balances::Trait for Runtime { type DustRemoval = (); type TransferPayment = (); type ExistentialDeposit = ExistentialDeposit; - type TransferFee = TransferFee; type CreationFee = CreationFee; } diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index e5e453fcaff04..a23359e6f9504 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -167,7 +167,6 @@ impl pallet_indices::Trait for Runtime { parameter_types! { pub const ExistentialDeposit: Balance = 1 * DOLLARS; - pub const TransferFee: Balance = 1 * CENTS; pub const CreationFee: Balance = 1 * CENTS; } @@ -180,7 +179,6 @@ impl pallet_balances::Trait for Runtime { type DustRemoval = (); type TransferPayment = (); type ExistentialDeposit = ExistentialDeposit; - type TransferFee = TransferFee; type CreationFee = CreationFee; } @@ -431,7 +429,6 @@ impl pallet_contracts::Trait for Runtime { type RentByteFee = RentByteFee; type RentDepositOffset = RentDepositOffset; type SurchargeReward = SurchargeReward; - type TransferFee = ContractTransferFee; type CreationFee = ContractCreationFee; type TransactionBaseFee = ContractTransactionBaseFee; type TransactionByteFee = ContractTransactionByteFee; diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 17d5d637b3ce8..c434965d4ad1f 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -159,10 +159,10 @@ #![cfg_attr(not(feature = "std"), no_std)] use sp_std::prelude::*; -use sp_std::{cmp, result, mem, fmt::Debug}; +use sp_std::{cmp, result, mem, fmt::Debug, ops::BitOr}; use codec::{Codec, Encode, Decode}; use frame_support::{ - StorageValue, Parameter, decl_event, decl_storage, decl_module, decl_error, + StorageValue, Parameter, decl_event, decl_storage, decl_module, decl_error, ensure, traits::{ UpdateBalanceOutcome, Currency, OnFreeBalanceZero, OnReapAccount, OnUnbalanced, TryDrop, WithdrawReason, WithdrawReasons, LockIdentifier, LockableCurrency, ExistenceRequirement, @@ -209,10 +209,8 @@ pub trait Subtrait: frame_system::Trait { /// The minimum amount required to keep an account open. type ExistentialDeposit: Get; - /// The fee required to make a transfer. - type TransferFee: Get; - - /// The fee required to create an account. + /// The fee required to create an account. If you're doing significant stuff with `OnNewAccount` + /// then you'll probably want to make this non-zero. type CreationFee: Get; } @@ -249,9 +247,6 @@ pub trait Trait: frame_system::Trait { /// The minimum amount required to keep an account open. type ExistentialDeposit: Get; - /// The fee required to make a transfer. - type TransferFee: Get; - /// The fee required to create an account. type CreationFee: Get; } @@ -262,7 +257,6 @@ impl, I: Instance> Subtrait for T { type OnReapAccount = T::OnReapAccount; type OnNewAccount = T::OnNewAccount; type ExistentialDeposit = T::ExistentialDeposit; - type TransferFee = T::TransferFee; type CreationFee = T::CreationFee; } @@ -333,11 +327,101 @@ impl Ves } } +/// Simplified reasons for withdrawing balance. +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug)] +pub enum Reasons { + /// Paying system transaction fees. + Fee = 0, + /// Any reason other than paying system transaction fees. + Misc = 1, + /// Any reason at all. + All = 2, +} + +impl From for Reasons { + fn from(r: WithdrawReasons) -> Reasons { + if r == WithdrawReasons::from(WithdrawReason::TransactionPayment) { + Reasons::Fee + } else if r.contains(WithdrawReason::TransactionPayment) { + Reasons::All + } else { + Reasons::Misc + } + } +} + +impl BitOr for Reasons { + type Output = Reasons; + fn bitor(self, other: Reasons) -> Reasons { + if self == other { return self } + Reasons::All + } +} + +/// A single lock on a balance. There can be many of these on an account and they "overlap", so the +/// same balance is frozen by multiple locks. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] pub struct BalanceLock { + /// An identifier for this lock. Only one lock may be in existence for each identifier. pub id: LockIdentifier, + /// The amount which the free balance may not drop below when this lock is in effect. pub amount: Balance, - pub reasons: WithdrawReasons, + /// If true, then the lock remains in effect even for payment of transaction fees. + pub reasons: Reasons, +} + +/// All balance information for an account. +#[derive(Encode, Decode, Clone, PartialEq, Eq, Default, RuntimeDebug)] +pub struct Account { + /// Non-reserved part of the balance. There may still be restrictions on this, but it is the + /// total pool what may in principle be transferred, reserved and used for tipping. + /// + /// This is the only balance that matters in terms of most operations on tokens. It + /// alone is used to determine the balance when in the contract execution environment. When this + /// balance falls below the value of `ExistentialDeposit`, then the 'current account' is + /// deleted: specifically `free`. Further, the `OnFreeBalanceZero` callback + /// is invoked, giving a chance to external modules to clean up data associated with + /// the deleted account. + /// + /// `frame_system::AccountNonce` is also deleted if `reserved` is also zero (it also gets + /// collapsed to zero if it ever becomes less than `ExistentialDeposit`. + pub free: Balance, + /// Balance which is reserved and may not be used at all. + /// + /// This can still get slashed, but gets slashed last of all. + /// + /// This balance is a 'reserve' balance that other subsystems use in order to set aside tokens + /// that are still 'owned' by the account holder, but which are suspendable. + /// + /// When this balance falls below the value of `ExistentialDeposit`, then any remainder is + /// coalesced into `free`. + pub reserved: Balance, + /// The amount that `free` may not drop below when withdrawing for *anything except transaction + /// fee payment*. + pub misc_frozen: Balance, + /// The amount that `free` may not drop below when withdrawing specifically for transaction + /// fee payment. + pub fee_frozen: Balance, +} + +impl Account { + /// How much this account's balance can be reduced for the given `reasons`. + pub fn usable(&self, reasons: Reasons) -> Balance { + self.free.saturating_sub(self.frozen(reasons)) + } + /// The amount that this account's free balance may not be reduced beyond for the given + /// `reasons`. + fn frozen(&self, reasons: Reasons) -> Balance { + match reasons { + Reasons::All => self.misc_frozen.max(self.fee_frozen), + Reasons::Misc => self.misc_frozen, + Reasons::Fee => self.fee_frozen, + } + } + /// The total balance in this account including any that is reserved and ignoring any frozen. + fn total(&self) -> Balance { + self.free.saturating_add(self.reserved) + } } decl_storage! { @@ -376,45 +460,26 @@ decl_storage! { }).collect::>() }): map T::AccountId => Option>; + /// The balance of an account. + pub Balance get(fn balance) + build(|config: &GenesisConfig| config.balances.iter() + .map(|&(ref who, free)| (who.clone(), Account { free, .. Default::default() })) + .collect::>() + ): map T::AccountId => Account; + // TODO: amalgamate the next two into a single item, and also include: // - fees-locked (min balance to be kept regarding payment of fees - paying a // fee may not result in the balance being reduced to below this amount) - // - tips-locked (min balance to be kept when paying tx tip) - // - transfer-locked (min balance to be kept when transferring) - // - reserve-locked (min balance to be kept when reserving) - // consider combining the last three and only have fees and non-fees. - - /// The 'free' balance of a given account. - /// - /// This is the only balance that matters in terms of most operations on tokens. It - /// alone is used to determine the balance when in the contract execution environment. When this - /// balance falls below the value of `ExistentialDeposit`, then the 'current account' is - /// deleted: specifically `FreeBalance`. Further, the `OnFreeBalanceZero` callback - /// is invoked, giving a chance to external modules to clean up data associated with - /// the deleted account. - /// - /// `frame_system::AccountNonce` is also deleted if `ReservedBalance` is also zero (it also gets - /// collapsed to zero if it ever becomes less than `ExistentialDeposit`. - pub FreeBalance get(fn free_balance) - build(|config: &GenesisConfig| config.balances.clone()): - map T::AccountId => T::Balance; - - /// The amount of the balance of a given account that is externally reserved; this can still get - /// slashed, but gets slashed last of all. - /// - /// This balance is a 'reserve' balance that other subsystems use in order to set aside tokens - /// that are still 'owned' by the account holder, but which are suspendable. - /// - /// When this balance falls below the value of `ExistentialDeposit`, then this 'reserve account' - /// is deleted: specifically, `ReservedBalance`. - /// - /// `frame_system::AccountNonce` is also deleted if `FreeBalance` is also zero (it also gets - /// collapsed to zero if it ever becomes less than `ExistentialDeposit`.) - pub ReservedBalance get(fn reserved_balance): map T::AccountId => T::Balance; + // - locked (min balance to be kept for any other use) /// Any liquidity locks on some account balances. /// NOTE: Should only be accessed when setting, changing and freeing a lock. pub Locks get(fn locks): map T::AccountId => Vec>; + + // TODO: Will need to be migrated from the old BalanceLock format on Kusama + + /// True if network has been upgraded to this version. + IsUpgraded: bool; } add_extra_genesis { config(balances): Vec<(T::AccountId, T::Balance)>; @@ -438,9 +503,6 @@ decl_module! { /// The minimum amount required to keep an account open. const ExistentialDeposit: T::Balance = T::ExistentialDeposit::get(); - /// The fee required to make a transfer. - const TransferFee: T::Balance = T::TransferFee::get(); - /// The fee required to create an account. const CreationFee: T::Balance = T::CreationFee::get(); @@ -509,23 +571,24 @@ decl_module! { let new_free = if new_free < existential_deposit { Zero::zero() } else { new_free }; let new_reserved = if new_reserved < existential_deposit { Zero::zero() } else { new_reserved }; - let current_free = >::get(&who); - if new_free > current_free { - mem::drop(PositiveImbalance::::new(new_free - current_free)); - } else if new_free < current_free { - mem::drop(NegativeImbalance::::new(current_free - new_free)); + let account = Balance::::get(&who); + + if new_free > account.free { + mem::drop(PositiveImbalance::::new(new_free - account.free)); + } else if new_free < account.free { + mem::drop(NegativeImbalance::::new(account.free - new_free)); } - Self::set_free_balance(&who, new_free); - let current_reserved = >::get(&who); - if new_reserved > current_reserved { - mem::drop(PositiveImbalance::::new(new_reserved - current_reserved)); - } else if new_reserved < current_reserved { - mem::drop(NegativeImbalance::::new(current_reserved - new_reserved)); + if new_reserved > account.reserved { + mem::drop(PositiveImbalance::::new(new_reserved - account.reserved)); + } else if new_reserved < account.reserved { + mem::drop(NegativeImbalance::::new(account.reserved - new_reserved)); } - Self::set_reserved_balance(&who, new_reserved); - Self::deposit_event(RawEvent::BalanceSet(who, new_free, new_reserved)); + let account = Account { free: new_free, reserved: new_reserved, .. account }; + Balance::::insert(&who, &account); + + Self::deposit_event(RawEvent::BalanceSet(who, account.free, account.reserved)); } /// Exactly as `transfer`, except the origin must be root and the source account may be @@ -575,12 +638,10 @@ impl, I: Instance> Module { /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that /// the caller will do this. fn set_reserved_balance(who: &T::AccountId, balance: T::Balance) -> UpdateBalanceOutcome { + Balance::::mutate(who, |b| b.reserved = balance); if balance < T::ExistentialDeposit::get() { - >::insert(who, balance); - Self::on_reserved_too_low(who); - UpdateBalanceOutcome::AccountKilled + Self::on_reserved_too_low(who) } else { - >::insert(who, balance); UpdateBalanceOutcome::Updated } } @@ -597,12 +658,41 @@ impl, I: Instance> Module { // Commented out for now - but consider it instructive. // assert!(!Self::total_balance(who).is_zero()); // assert!(Self::free_balance(who) > T::ExistentialDeposit::get()); + Balance::::mutate(who, |b| b.free = balance); if balance < T::ExistentialDeposit::get() { - >::insert(who, balance); - Self::on_free_too_low(who); - UpdateBalanceOutcome::AccountKilled + Self::on_free_too_low(who) + } else { + UpdateBalanceOutcome::Updated + } + } + + /// Set both the free and reserved balance of an account to some new value. Will enforce + /// `ExistentialDeposit` law, annulling the account as needed. + /// + /// Will return `AccountKilled` if either reserved or free are too low. + /// + /// This is generally faster than calling `set_free_balance` or `set_reserved_balance` since + /// it avoids the need for a storage `get`. It should be used in preference when an up-to-date + /// `Account` value is available. + /// + /// NOTE: This assumes that `account` is the same as `Self::balance(who)` except for altered + /// values of `free` and `balance`. + /// + /// NOTE: Doesn't do any preparatory work for creating a new account, so should only be used + /// when it is known that the account already exists. + /// + /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that + /// the caller will do this. + fn set_balances(who: &T::AccountId, account: &Account) -> UpdateBalanceOutcome { + // Commented out for now - but consider it instructive. + // assert!(!Self::total_balance(who).is_zero()); + // assert!(Self::free_balance(who) > T::ExistentialDeposit::get()); + Balance::::insert(who, account); + if account.free < T::ExistentialDeposit::get() { + Self::on_free_too_low(who) + } else if account.reserved < T::ExistentialDeposit::get() { + Self::on_reserved_too_low(who) } else { - >::insert(who, balance); UpdateBalanceOutcome::Updated } } @@ -610,7 +700,7 @@ impl, I: Instance> Module { /// Register a new account (with existential balance). /// /// This just calls appropriate hooks. It doesn't (necessarily) make any state changes. - fn new_account(who: &T::AccountId, balance: T::Balance) { + fn about_to_create_account(who: &T::AccountId, balance: T::Balance) { T::OnNewAccount::on_new_account(&who); Self::deposit_event(RawEvent::NewAccount(who.clone(), balance.clone())); } @@ -619,6 +709,8 @@ impl, I: Instance> Module { /// /// This just removes the nonce and leaves an event. fn reap_account(who: &T::AccountId, dust: T::Balance) { + Locks::::remove(who); + Balance::::remove(who); T::OnReapAccount::on_reap_account(who); Self::deposit_event(RawEvent::ReapedAccount(who.clone(), dust)); } @@ -627,27 +719,30 @@ impl, I: Instance> Module { /// free side and the account completely if its reserved size is already dead. /// /// Will maintain total issuance. - fn on_free_too_low(who: &T::AccountId) { - let dust = >::take(who); - >::remove(who); - - T::OnFreeBalanceZero::on_free_balance_zero(who); - - let mut reserved_balance = Self::reserved_balance(who); - - if !dust.is_zero() { - if reserved_balance >= T::ExistentialDeposit::get() { + fn on_free_too_low(who: &T::AccountId) -> UpdateBalanceOutcome { + let mut b = Balance::::get(who); + let mut dust = Zero::zero(); + if !b.free.is_zero() { + if b.reserved >= T::ExistentialDeposit::get() { // any individual account cannot cause overflow in balance. - reserved_balance += dust; - Self::set_reserved_balance(who, reserved_balance); + b.reserved += b.free; } else { // underflow should never happen, but if it does, there's not much we can do. + dust = b.free + b.reserved; T::DustRemoval::on_unbalanced(NegativeImbalance::new(dust)); + b.reserved = Zero::zero(); } + b.free = Zero::zero(); } + Balance::::insert(who, &b); + + T::OnFreeBalanceZero::on_free_balance_zero(who); - if reserved_balance.is_zero() { + if b.reserved.is_zero() { Self::reap_account(who, dust); + UpdateBalanceOutcome::AccountKilled + } else { + UpdateBalanceOutcome::FreeBalanceZero } } @@ -655,26 +750,48 @@ impl, I: Instance> Module { /// reserved side and the account completely if its free size is already dead. /// /// Will maintain total issuance. - fn on_reserved_too_low(who: &T::AccountId) { - let dust = >::take(who); + fn on_reserved_too_low(who: &T::AccountId) -> UpdateBalanceOutcome { + let mut b = Balance::::get(who); + let mut dust = Zero::zero(); - let mut free_balance = Self::free_balance(who); - - if !dust.is_zero() { - if free_balance >= T::ExistentialDeposit::get() { + if !b.reserved.is_zero() { + if b.free >= T::ExistentialDeposit::get() { // any individual account cannot cause overflow in balance. - free_balance += dust; - Self::set_free_balance(who, free_balance); + b.free += b.reserved; } else { - // underflow should never happen, but it if does, there's nothing to be done here. + // underflow should never happen, but if it does, there's not much we can do. + dust = b.free + b.reserved; T::DustRemoval::on_unbalanced(NegativeImbalance::new(dust)); + b.free = Zero::zero(); } + b.reserved = Zero::zero(); } + Balance::::insert(who, &b); - if free_balance.is_zero() { + if b.free.is_zero() { Self::reap_account(who, dust); + UpdateBalanceOutcome::AccountKilled + } else { + UpdateBalanceOutcome::ReservedBalanceZero } } + + /// Update the account entry for `who`, given the locks. + fn update_locks(who: &T::AccountId, locks: &[BalanceLock]) { + Balance::::mutate(who, |b| { + b.misc_frozen = Zero::zero(); + b.fee_frozen = Zero::zero(); + for l in locks.iter() { + if l.reasons == Reasons::All || l.reasons == Reasons::Misc { + b.misc_frozen = b.misc_frozen.max(l.amount); + } + if l.reasons == Reasons::All || l.reasons == Reasons::Fee { + b.fee_frozen = b.fee_frozen.max(l.amount); + } + } + }); + Locks::::insert(who, locks); + } } // wrapping these imbalances in a private module is necessary to ensure absolute privacy @@ -878,7 +995,6 @@ impl, I: Instance> Trait for ElevatedTrait { type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = T::ExistentialDeposit; - type TransferFee = T::TransferFee; type CreationFee = T::CreationFee; } @@ -891,11 +1007,10 @@ where type NegativeImbalance = NegativeImbalance; fn total_balance(who: &T::AccountId) -> Self::Balance { - Self::free_balance(who) + Self::reserved_balance(who) + Self::balance(who).total() } // Check if `value` amount of free balance can be slashed from `who`. - // Is a no-op if value to be slashed is zero. fn can_slash(who: &T::AccountId, value: Self::Balance) -> bool { if value.is_zero() { return true } Self::free_balance(who) >= value @@ -910,7 +1025,7 @@ where } fn free_balance(who: &T::AccountId) -> Self::Balance { - >::get(who) + Balance::::get(who).free } // Burn funds from the total issuance, returning a positive imbalance for the amount burned. @@ -955,17 +1070,16 @@ where new_balance: T::Balance, ) -> DispatchResult { if amount.is_zero() { return Ok(()) } + + // TODO: remove once there's a vesting pallet. if reasons.intersects(WithdrawReason::Reserve | WithdrawReason::Transfer) && Self::vesting_balance(who) > new_balance { Err(Error::::VestingBalance)? } - let locks = Self::locks(who); - if locks.is_empty() { - return Ok(()) - } - if locks.into_iter().all(|l| new_balance >= l.amount || !l.reasons.intersects(reasons)) { + let reasons = reasons.into(); + if new_balance >= Balance::::get(who).frozen(reasons) { Ok(()) } else { Err(Error::::LiquidityRestrictions.into()) @@ -973,50 +1087,55 @@ where } // Transfer some free balance from `transactor` to `dest`, respecting existence requirements. - // Is a no-op if value to be transferred is zero. + // Is a no-op if value to be transferred is zero or the `transactor` is the same as `dest`. fn transfer( transactor: &T::AccountId, dest: &T::AccountId, value: Self::Balance, existence_requirement: ExistenceRequirement, ) -> DispatchResult { - if value.is_zero() { return Ok(()) } - let from_balance = Self::free_balance(transactor); - let to_balance = Self::free_balance(dest); - let would_create = to_balance.is_zero(); - let fee = if would_create { T::CreationFee::get() } else { T::TransferFee::get() }; + if value.is_zero() || transactor == dest { return Ok(()) } + + let mut from_balance = Self::balance(transactor); + let mut to_balance = Self::balance(dest); + + let would_create = to_balance.total().is_zero(); + let fee = if would_create { T::CreationFee::get() } else { Zero::zero() }; let liability = value.checked_add(&fee).ok_or(Error::::Overflow)?; - let new_from_balance = from_balance.checked_sub(&liability).ok_or(Error::::InsufficientBalance)?; - if would_create && value < T::ExistentialDeposit::get() { - Err(Error::::ExistentialDeposit)? - } - Self::ensure_can_withdraw(transactor, value, WithdrawReason::Transfer.into(), new_from_balance)?; + from_balance.free = from_balance.free.checked_sub(&liability) + .ok_or(Error::::InsufficientBalance)?; // NOTE: total stake being stored in the same type means that this could never overflow // but better to be safe than sorry. - let new_to_balance = to_balance.checked_add(&value).ok_or(Error::::Overflow)?; + to_balance.free = to_balance.free.checked_add(&value).ok_or(Error::::Overflow)?; - if transactor != dest { - if existence_requirement == ExistenceRequirement::KeepAlive { - if new_from_balance < Self::minimum_balance() { - Err(Error::::KeepAlive)? - } - } + let ed = T::ExistentialDeposit::get(); + ensure!(to_balance.free >= ed, Error::::ExistentialDeposit); - Self::set_free_balance(transactor, new_from_balance); - if !>::exists(dest) { - Self::new_account(dest, new_to_balance); - } + Self::ensure_can_withdraw( + transactor, + value, + WithdrawReason::Transfer.into(), + from_balance.free, + )?; + + let allow_death = existence_requirement == ExistenceRequirement::AllowDeath; + ensure!(allow_death || from_balance.free >= ed, Error::::KeepAlive); - // Emit transfer event. - Self::deposit_event(RawEvent::Transfer(transactor.clone(), dest.clone(), value, fee)); + Self::set_balances(transactor, &from_balance); - // Take action on the set_free_balance call. - // This will emit events that _resulted_ from the transfer. - Self::set_free_balance(dest, new_to_balance); - T::TransferPayment::on_unbalanced(NegativeImbalance::new(fee)); + // Emit transfer event. + Self::deposit_event(RawEvent::Transfer(transactor.clone(), dest.clone(), value, fee)); + + if would_create { + Self::about_to_create_account(dest, to_balance.free); } + // Take action on the set_free_balance call. + // This will emit events that _resulted_ from the transfer. + Self::set_balances(dest, &to_balance); + + T::TransferPayment::on_unbalanced(NegativeImbalance::new(fee)); Ok(()) } @@ -1031,6 +1150,8 @@ where ) -> result::Result { if value.is_zero() { return Ok(NegativeImbalance::zero()); } + // TODO: rewrite using composite balance. + let old_balance = Self::free_balance(who); if let Some(new_balance) = old_balance.checked_sub(&value) { // if we need to keep the account alive... @@ -1059,6 +1180,8 @@ where ) -> (Self::NegativeImbalance, Self::Balance) { if value.is_zero() { return (NegativeImbalance::zero(), Zero::zero()) } + // TODO: rewrite using composite balance. + let free_balance = Self::free_balance(who); let free_slash = cmp::min(free_balance, value); @@ -1086,6 +1209,8 @@ where ) -> result::Result { if value.is_zero() { return Ok(PositiveImbalance::zero()) } + // TODO: rewrite using composite balance. + if Self::total_balance(who).is_zero() { Err(Error::::DeadAccount)? } @@ -1101,6 +1226,8 @@ where ) -> Self::PositiveImbalance { if value.is_zero() { return Self::PositiveImbalance::zero() } + // TODO: rewrite using composite balance. + let (imbalance, _) = Self::make_free_balance_be(who, Self::free_balance(who) + value); if let SignedImbalance::Positive(p) = imbalance { p @@ -1114,6 +1241,8 @@ where SignedImbalance, UpdateBalanceOutcome ) { + // TODO: rewrite using composite balance. + let original = Self::free_balance(who); if balance < T::ExistentialDeposit::get() && original.is_zero() { // If we're attempting to set an existing account to less than ED, then @@ -1145,8 +1274,8 @@ where Self::set_free_balance(who, balance); UpdateBalanceOutcome::AccountKilled } else { - if !>::exists(who) { - Self::new_account(&who, balance); + if !Balance::::exists(who) { + Self::about_to_create_account(&who, balance); } Self::set_free_balance(who, balance); UpdateBalanceOutcome::Updated @@ -1171,13 +1300,16 @@ where } fn reserved_balance(who: &T::AccountId) -> Self::Balance { - >::get(who) + Balance::::get(who).reserved } // Move `value` from the free balance from `who` to their reserved balance. // Is a no-op if value to be reserved is zero. fn reserve(who: &T::AccountId, value: Self::Balance) -> result::Result<(), DispatchError> { if value.is_zero() { return Ok(()) } + + // TODO: rewrite using composite balance. + let b = Self::free_balance(who); if b < value { Err(Error::::InsufficientBalance)? @@ -1193,6 +1325,9 @@ where // Is a no-op if the value to be unreserved is zero. fn unreserve(who: &T::AccountId, value: Self::Balance) -> Self::Balance { if value.is_zero() { return Zero::zero() } + + // TODO: rewrite using composite balance. + let b = Self::reserved_balance(who); let actual = cmp::min(b, value); Self::set_free_balance(who, Self::free_balance(who) + actual); @@ -1208,6 +1343,9 @@ where value: Self::Balance ) -> (Self::NegativeImbalance, Self::Balance) { if value.is_zero() { return (NegativeImbalance::zero(), Zero::zero()) } + + // TODO: rewrite using composite balance. + let b = Self::reserved_balance(who); let slash = cmp::min(b, value); // underflow should never happen, but it if does, there's nothing to be done here. @@ -1223,6 +1361,9 @@ where value: Self::Balance, ) -> result::Result { if value.is_zero() { return Ok (Zero::zero()) } + + // TODO: rewrite using composite balance. + if Self::total_balance(beneficiary).is_zero() { Err(Error::::DeadAccount)? } @@ -1241,15 +1382,15 @@ where type Moment = T::BlockNumber; // Set a lock on the balance of `who`. - // Is a no-op if lock amount is zero. + // Is a no-op if lock amount is zero or `reasons` `is_none()`. fn set_lock( id: LockIdentifier, who: &T::AccountId, amount: T::Balance, reasons: WithdrawReasons, ) { - if amount.is_zero() { return } - let mut new_lock = Some(BalanceLock { id, amount, reasons }); + if amount.is_zero() || reasons.is_none() { return } + let mut new_lock = Some(BalanceLock { id, amount, reasons: reasons.into() }); let mut locks = Self::locks(who).into_iter().filter_map(|l| if l.id == id { new_lock.take() @@ -1259,16 +1400,19 @@ where if let Some(lock) = new_lock { locks.push(lock) } - >::insert(who, locks); + Self::update_locks(who, &locks[..]); } + // Extend a lock on the balance of `who`. + // Is a no-op if lock amount is zero or `reasons` `is_none()`. fn extend_lock( id: LockIdentifier, who: &T::AccountId, amount: T::Balance, reasons: WithdrawReasons, ) { - let mut new_lock = Some(BalanceLock { id, amount, reasons }); + if amount.is_zero() || reasons.is_none() { return } + let mut new_lock = Some(BalanceLock { id, amount, reasons: reasons.into() }); let mut locks = Self::locks(who).into_iter().filter_map(|l| if l.id == id { new_lock.take().map(|nl| { @@ -1284,7 +1428,7 @@ where if let Some(lock) = new_lock { locks.push(lock) } - >::insert(who, locks); + Self::update_locks(who, &locks[..]); } fn remove_lock( @@ -1293,7 +1437,7 @@ where ) { let mut locks = Self::locks(who); locks.retain(|l| l.id != id); - >::insert(who, locks); + Self::update_locks(who, &locks[..]); } } @@ -1348,6 +1492,6 @@ where T::Balance: MaybeSerializeDeserialize + Debug { fn is_dead_account(who: &T::AccountId) -> bool { - Self::total_balance(who).is_zero() + !Balance::::exists(who) } } diff --git a/frame/balances/src/mock.rs b/frame/balances/src/mock.rs index 5a3d671e8dbc9..e16462154f936 100644 --- a/frame/balances/src/mock.rs +++ b/frame/balances/src/mock.rs @@ -32,7 +32,6 @@ impl_outer_origin!{ thread_local! { pub(crate) static EXISTENTIAL_DEPOSIT: RefCell = RefCell::new(0); - static TRANSFER_FEE: RefCell = RefCell::new(0); static CREATION_FEE: RefCell = RefCell::new(0); } @@ -41,11 +40,6 @@ impl Get for ExistentialDeposit { fn get() -> u64 { EXISTENTIAL_DEPOSIT.with(|v| *v.borrow()) } } -pub struct TransferFee; -impl Get for TransferFee { - fn get() -> u64 { TRANSFER_FEE.with(|v| *v.borrow()) } -} - pub struct CreationFee; impl Get for CreationFee { fn get() -> u64 { CREATION_FEE.with(|v| *v.borrow()) } @@ -99,13 +93,11 @@ impl Trait for Test { type DustRemoval = (); type TransferPayment = (); type ExistentialDeposit = ExistentialDeposit; - type TransferFee = TransferFee; type CreationFee = CreationFee; } pub struct ExtBuilder { existential_deposit: u64, - transfer_fee: u64, creation_fee: u64, monied: bool, vesting: bool, @@ -114,7 +106,6 @@ impl Default for ExtBuilder { fn default() -> Self { Self { existential_deposit: 0, - transfer_fee: 0, creation_fee: 0, monied: false, vesting: false, @@ -126,11 +117,6 @@ impl ExtBuilder { self.existential_deposit = existential_deposit; self } - #[allow(dead_code)] - pub fn transfer_fee(mut self, transfer_fee: u64) -> Self { - self.transfer_fee = transfer_fee; - self - } pub fn creation_fee(mut self, creation_fee: u64) -> Self { self.creation_fee = creation_fee; self @@ -148,7 +134,6 @@ impl ExtBuilder { } pub fn set_associated_consts(&self) { EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit); - TRANSFER_FEE.with(|v| *v.borrow_mut() = self.transfer_fee); CREATION_FEE.with(|v| *v.borrow_mut() = self.creation_fee); } pub fn build(self) -> sp_io::TestExternalities { @@ -187,5 +172,5 @@ pub const CALL: &::Call = &(); /// create a transaction info struct from weight. Handy to avoid building the whole struct. pub fn info_from_weight(w: Weight) -> DispatchInfo { - DispatchInfo { weight: w, ..Default::default() } + DispatchInfo { weight: w, pays_fee: true, ..Default::default() } } diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index 111160950f4b0..02fbd94f98df3 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -18,7 +18,7 @@ use super::*; use mock::{Balances, ExtBuilder, Test, System, info_from_weight, CALL}; -use sp_runtime::traits::{SignedExtension, BadOrigin}; +use sp_runtime::{Fixed64, traits::{SignedExtension, BadOrigin}}; use frame_support::{ assert_noop, assert_ok, assert_err, traits::{LockableCurrency, LockIdentifier, WithdrawReason, WithdrawReasons, @@ -114,23 +114,12 @@ fn lock_reasons_should_work() { .monied(true) .build() .execute_with(|| { - Balances::set_lock(ID_1, &1, 10, WithdrawReason::Transfer.into()); + pallet_transaction_payment::NextFeeMultiplier::put(Fixed64::from_natural(1)); + Balances::set_lock(ID_1, &1, 10, WithdrawReason::Reserve.into()); assert_noop!( >::transfer(&1, &2, 1, AllowDeath), Error::::LiquidityRestrictions ); - assert_ok!(>::reserve(&1, 1)); - // NOTE: this causes a fee payment. - assert!( as SignedExtension>::pre_dispatch( - ChargeTransactionPayment::from(1), - &1, - CALL, - info_from_weight(1), - 0, - ).is_ok()); - - Balances::set_lock(ID_1, &1, 10, WithdrawReason::Reserve.into()); - assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); assert_noop!( >::reserve(&1, 1), Error::::LiquidityRestrictions @@ -140,7 +129,14 @@ fn lock_reasons_should_work() { &1, CALL, info_from_weight(1), - 0, + 1, + ).is_err()); + assert!( as SignedExtension>::pre_dispatch( + ChargeTransactionPayment::from(0), + &1, + CALL, + info_from_weight(1), + 1, ).is_ok()); Balances::set_lock(ID_1, &1, 10, WithdrawReason::TransactionPayment.into()); @@ -151,7 +147,14 @@ fn lock_reasons_should_work() { &1, CALL, info_from_weight(1), - 0, + 1, + ).is_err()); + assert!( as SignedExtension>::pre_dispatch( + ChargeTransactionPayment::from(0), + &1, + CALL, + info_from_weight(1), + 1, ).is_err()); }); } @@ -487,8 +490,8 @@ fn transferring_incomplete_reserved_balance_should_work() { #[test] fn transferring_too_high_value_should_not_panic() { ExtBuilder::default().build().execute_with(|| { - >::insert(1, u64::max_value()); - >::insert(2, 1); + >::insert(1, Account { free: u64::max_value(), .. Default::default() }); + >::insert(2, Account { free: 1, .. Default::default() }); assert_err!( Balances::transfer(Some(1).into(), 2, u64::max_value()), @@ -764,16 +767,16 @@ fn dust_moves_between_free_and_reserved() { assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 100, 100)); assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 2, 100, 100)); // Check balance - assert_eq!(Balances::free_balance(1), 100); - assert_eq!(Balances::reserved_balance(1), 100); - assert_eq!(Balances::free_balance(2), 100); - assert_eq!(Balances::reserved_balance(2), 100); + assert_eq!(Balances::free_balance(&1), 100); + assert_eq!(Balances::reserved_balance(&1), 100); + assert_eq!(Balances::free_balance(&2), 100); + assert_eq!(Balances::reserved_balance(&2), 100); // Drop 1 free_balance below ED assert_ok!(Balances::transfer(Some(1).into(), 2, 1)); // Check balance, the other 99 should move to reserved_balance - assert_eq!(Balances::free_balance(1), 0); - assert_eq!(Balances::reserved_balance(1), 199); + assert_eq!(Balances::free_balance(&1), 0); + assert_eq!(Balances::reserved_balance(&1), 199); // Reset accounts assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 100, 100)); @@ -782,13 +785,13 @@ fn dust_moves_between_free_and_reserved() { // Drop 2 reserved_balance below ED Balances::unreserve(&2, 1); // Check balance, all 100 should move to free_balance - assert_eq!(Balances::free_balance(2), 200); - assert_eq!(Balances::reserved_balance(2), 0); + assert_eq!(Balances::free_balance(&2), 200); + assert_eq!(Balances::reserved_balance(&2), 0); // An account with both too little free and reserved is completely killed assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 99, 99)); // Check balance is 0 for everything - assert_eq!(Balances::free_balance(1), 0); - assert_eq!(Balances::reserved_balance(1), 0); + assert_eq!(Balances::free_balance(&1), 0); + assert_eq!(Balances::reserved_balance(&1), 0); }); } diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index df8da8866020d..bc5ab186c0b13 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -400,9 +400,6 @@ pub trait Trait: frame_system::Trait { /// to removal of a contract. type SurchargeReward: Get>; - /// The fee required to make a transfer. - type TransferFee: Get>; - /// The fee required to create an account. type CreationFee: Get>; @@ -519,9 +516,6 @@ decl_module! { /// to removal of a contract. const SurchargeReward: BalanceOf = T::SurchargeReward::get(); - /// The fee required to make a transfer. - const TransferFee: BalanceOf = T::TransferFee::get(); - /// The fee required to create an account. const CreationFee: BalanceOf = T::CreationFee::get(); diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 91679a9216a16..f24478445d705 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -128,7 +128,6 @@ impl pallet_balances::Trait for Test { type DustRemoval = (); type TransferPayment = (); type ExistentialDeposit = ExistentialDeposit; - type TransferFee = TransferFee; type CreationFee = CreationFee; } parameter_types! { @@ -171,7 +170,6 @@ impl Trait for Test { type RentByteFee = RentByteFee; type RentDepositOffset = RentDepositOffset; type SurchargeReward = SurchargeReward; - type TransferFee = TransferFee; type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index d10162246c3d5..6b4569d7ca4d6 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -1222,7 +1222,6 @@ mod tests { } parameter_types! { pub const ExistentialDeposit: u64 = 0; - pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; } impl pallet_balances::Trait for Test { @@ -1234,7 +1233,6 @@ mod tests { type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; - type TransferFee = TransferFee; type CreationFee = CreationFee; } parameter_types! { diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index c5dc5689d9011..85f86fe771cb4 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -83,7 +83,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use sp_std::prelude::*; -use sp_runtime::{print, DispatchResult, DispatchError, traits::{Zero, StaticLookup, Bounded, Convert}}; +use sp_runtime::{print, DispatchResult, DispatchError, traits::{Zero, StaticLookup, Convert}}; use frame_support::{ decl_storage, decl_event, ensure, decl_module, decl_error, weights::SimpleDispatchInfo, traits::{ @@ -815,7 +815,6 @@ mod tests { parameter_types! { pub const ExistentialDeposit: u64 = 1; - pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; } @@ -828,7 +827,6 @@ mod tests { type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; - type TransferFee = TransferFee; type CreationFee = CreationFee; } diff --git a/frame/elections/src/lib.rs b/frame/elections/src/lib.rs index 9cc650591bba1..4d20dce9a982b 100644 --- a/frame/elections/src/lib.rs +++ b/frame/elections/src/lib.rs @@ -26,7 +26,7 @@ use sp_std::prelude::*; use sp_runtime::{ RuntimeDebug, DispatchResult, print, - traits::{Zero, One, StaticLookup, Bounded, Saturating}, + traits::{Zero, One, StaticLookup, Saturating}, }; use frame_support::{ decl_storage, decl_event, ensure, decl_module, decl_error, diff --git a/frame/elections/src/mock.rs b/frame/elections/src/mock.rs index 178637e088883..569e169beffff 100644 --- a/frame/elections/src/mock.rs +++ b/frame/elections/src/mock.rs @@ -58,7 +58,6 @@ impl frame_system::Trait for Test { parameter_types! { pub const ExistentialDeposit: u64 = 0; - pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; } impl pallet_balances::Trait for Test { @@ -70,7 +69,6 @@ impl pallet_balances::Trait for Test { type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; - type TransferFee = TransferFee; type CreationFee = CreationFee; } diff --git a/frame/example/src/lib.rs b/frame/example/src/lib.rs index 80569a1b57374..9cebed7de810b 100644 --- a/frame/example/src/lib.rs +++ b/frame/example/src/lib.rs @@ -689,7 +689,6 @@ mod tests { } parameter_types! { pub const ExistentialDeposit: u64 = 0; - pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; } impl pallet_balances::Trait for Test { @@ -701,7 +700,6 @@ mod tests { type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; - type TransferFee = TransferFee; type CreationFee = CreationFee; } impl Trait for Test { diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 0c3c2fe46ba82..54070f325c75b 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -455,7 +455,6 @@ mod tests { } parameter_types! { pub const ExistentialDeposit: u64 = 0; - pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; } impl pallet_balances::Trait for Runtime { @@ -467,7 +466,6 @@ mod tests { type DustRemoval = (); type TransferPayment = (); type ExistentialDeposit = ExistentialDeposit; - type TransferFee = TransferFee; type CreationFee = CreationFee; } diff --git a/frame/generic-asset/src/lib.rs b/frame/generic-asset/src/lib.rs index 4f602249e57ac..179335cde6fdf 100644 --- a/frame/generic-asset/src/lib.rs +++ b/frame/generic-asset/src/lib.rs @@ -805,10 +805,8 @@ impl Module { if locks.is_empty() { return Ok(()); } - let now = >::block_number(); if Self::locks(who) - .into_iter() - .all(|l| now >= l.until || new_balance >= l.amount || !l.reasons.intersects(reasons)) + .into_iter().all(|l| new_balance >= l.amount || !l.reasons.intersects(reasons)) { Ok(()) } else { @@ -889,7 +887,7 @@ impl Module { } fn remove_lock(id: LockIdentifier, who: &T::AccountId) { - let mut locks = >::locks(who) + let mut locks = >::locks(who); locks.retain(|l| l.id != id); >::insert(who, locks); } diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index b23407406b6a4..496c476faae28 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -914,7 +914,6 @@ mod tests { } parameter_types! { pub const ExistentialDeposit: u64 = 0; - pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; } impl pallet_balances::Trait for Test { @@ -926,7 +925,6 @@ mod tests { type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; - type TransferFee = TransferFee; type CreationFee = CreationFee; } parameter_types! { diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index 1d33d12ae4600..145ea2cc1a7d2 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -288,7 +288,6 @@ mod tests { } parameter_types! { pub const ExistentialDeposit: u64 = 0; - pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; } impl pallet_balances::Trait for Test { @@ -300,7 +299,6 @@ mod tests { type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; - type TransferFee = TransferFee; type CreationFee = CreationFee; } parameter_types! { diff --git a/frame/recovery/src/mock.rs b/frame/recovery/src/mock.rs index be9ed5c97e598..1da1d334aa582 100644 --- a/frame/recovery/src/mock.rs +++ b/frame/recovery/src/mock.rs @@ -81,7 +81,6 @@ impl frame_system::Trait for Test { parameter_types! { pub const ExistentialDeposit: u64 = 1; - pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; } @@ -94,7 +93,6 @@ impl pallet_balances::Trait for Test { type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; - type TransferFee = TransferFee; type CreationFee = CreationFee; } diff --git a/frame/scored-pool/src/mock.rs b/frame/scored-pool/src/mock.rs index dd59bbc84fe64..d22f0aa572ca1 100644 --- a/frame/scored-pool/src/mock.rs +++ b/frame/scored-pool/src/mock.rs @@ -47,7 +47,6 @@ parameter_types! { pub const AvailableBlockRatio: Perbill = Perbill::one(); pub const ExistentialDeposit: u64 = 0; - pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; } ord_parameter_types! { @@ -83,7 +82,6 @@ impl pallet_balances::Trait for Test { type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; - type TransferFee = TransferFee; type CreationFee = CreationFee; } diff --git a/frame/society/src/mock.rs b/frame/society/src/mock.rs index 3ce8938f95302..e61402c671bff 100644 --- a/frame/society/src/mock.rs +++ b/frame/society/src/mock.rs @@ -52,7 +52,6 @@ parameter_types! { pub const AvailableBlockRatio: Perbill = Perbill::one(); pub const ExistentialDeposit: u64 = 0; - pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; } @@ -88,7 +87,6 @@ impl pallet_balances::Trait for Test { type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; - type TransferFee = TransferFee; type CreationFee = CreationFee; type OnReapAccount = System; } diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 3c238b56ed317..0530eb55922bf 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -140,7 +140,6 @@ impl frame_system::Trait for Test { type ModuleToIndex = (); } parameter_types! { - pub const TransferFee: Balance = 0; pub const CreationFee: Balance = 0; } impl pallet_balances::Trait for Test { @@ -152,7 +151,6 @@ impl pallet_balances::Trait for Test { type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; - type TransferFee = TransferFee; type CreationFee = CreationFee; } parameter_types! { diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 7cc8def9e41a0..bf68d4a8e269e 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -84,6 +84,10 @@ pub enum UpdateBalanceOutcome { Updated, /// The update led to killing the account. AccountKilled, + /// Free balance became zero as a result of this update. + FreeBalanceZero, + /// Reserved balance became zero as a result of this update. + ReservedBalanceZero, } /// A trait for finding the author of a block header based on the `PreRuntime` digests contained @@ -641,7 +645,7 @@ bitmask! { TransactionPayment = 0b00000001, /// In order to transfer ownership. Transfer = 0b00000010, - /// In order to reserve some funds for a later return or repatriation + /// In order to reserve some funds for a later return or repatriation. Reserve = 0b00000100, /// In order to pay some other (higher-level) fees. Fee = 0b00001000, diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index fa73b0a9faf3e..7aa5c7dd0176f 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -76,7 +76,7 @@ pub trait Trait: frame_system::Trait { decl_storage! { trait Store for Module as Balances { - NextFeeMultiplier get(fn next_fee_multiplier): Multiplier = Multiplier::from_parts(0); + pub NextFeeMultiplier get(fn next_fee_multiplier): Multiplier = Multiplier::from_parts(0); } } @@ -306,7 +306,6 @@ mod tests { } parameter_types! { - pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; pub const ExistentialDeposit: u64 = 0; } @@ -320,7 +319,6 @@ mod tests { type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; - type TransferFee = TransferFee; type CreationFee = CreationFee; } diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index 1800d0ad04392..e098484f5b088 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -759,7 +759,6 @@ mod tests { } parameter_types! { pub const ExistentialDeposit: u64 = 1; - pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; } impl pallet_balances::Trait for Test { @@ -771,7 +770,6 @@ mod tests { type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; - type TransferFee = TransferFee; type CreationFee = CreationFee; } pub struct TenToFourteen; diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 9ab2975e29550..a8423551b7907 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -701,7 +701,6 @@ mod tests { } parameter_types! { pub const ExistentialDeposit: u64 = 0; - pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; } impl pallet_balances::Trait for Test { @@ -713,7 +712,6 @@ mod tests { type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; - type TransferFee = TransferFee; type CreationFee = CreationFee; } parameter_types! { From 281ae4343137b45b93ea493b92e99819304aa8e2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 22 Jan 2020 09:43:32 +0100 Subject: [PATCH 06/29] Split out vesting --- Cargo.lock | 16 ++ Cargo.toml | 1 + frame/balances/src/lib.rs | 133 +--------- frame/balances/src/tests.rs | 154 ----------- frame/contracts/src/lib.rs | 2 - frame/support/src/traits.rs | 14 +- frame/vesting/Cargo.toml | 31 +++ frame/vesting/src/lib.rs | 506 ++++++++++++++++++++++++++++++++++++ 8 files changed, 571 insertions(+), 286 deletions(-) create mode 100644 frame/vesting/Cargo.toml create mode 100644 frame/vesting/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 7a4ae1beea5af..c1b365426cf65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4105,6 +4105,22 @@ dependencies = [ "sp-std 2.0.0", ] +[[package]] +name = "pallet-vesting" +version = "2.0.0" +dependencies = [ + "enumflags2 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "frame-support 2.0.0", + "frame-system 2.0.0", + "pallet-balances 2.0.0", + "parity-scale-codec 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-core 2.0.0", + "sp-io 2.0.0", + "sp-runtime 2.0.0", + "sp-std 2.0.0", +] + [[package]] name = "parity-bytes" version = "0.1.1" diff --git a/Cargo.toml b/Cargo.toml index f6e521b9c5dbb..81da0090229b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,6 +98,7 @@ members = [ "frame/transaction-payment/rpc/runtime-api", "frame/treasury", "frame/utility", + "frame/vesting", "primitives/application-crypto", "primitives/application-crypto/test", "primitives/authority-discovery", diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index c434965d4ad1f..b63d296ee8811 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -166,7 +166,7 @@ use frame_support::{ traits::{ UpdateBalanceOutcome, Currency, OnFreeBalanceZero, OnReapAccount, OnUnbalanced, TryDrop, WithdrawReason, WithdrawReasons, LockIdentifier, LockableCurrency, ExistenceRequirement, - Imbalance, SignedImbalance, ReservableCurrency, Get, VestingCurrency, + Imbalance, SignedImbalance, ReservableCurrency, Get, }, weights::SimpleDispatchInfo, }; @@ -189,7 +189,7 @@ pub use self::imbalances::{PositiveImbalance, NegativeImbalance}; pub trait Subtrait: frame_system::Trait { /// The balance of an account. type Balance: Parameter + Member + SimpleArithmetic + Codec + Default + Copy + - MaybeSerializeDeserialize + Debug + From; + MaybeSerializeDeserialize + Debug; /// A function that is invoked when the free-balance has fallen below the existential deposit and /// has been reduced to zero. @@ -217,7 +217,7 @@ pub trait Subtrait: frame_system::Trait { pub trait Trait: frame_system::Trait { /// The balance of an account. type Balance: Parameter + Member + SimpleArithmetic + Codec + Default + Copy + - MaybeSerializeDeserialize + Debug + From; + MaybeSerializeDeserialize + Debug; /// A function that is invoked when the free-balance has fallen below the existential deposit and /// has been reduced to zero. @@ -299,34 +299,6 @@ decl_error! { } } -/// Struct to encode the vesting schedule of an individual account. -#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug)] -pub struct VestingSchedule { - /// Locked amount at genesis. - pub locked: Balance, - /// Amount that gets unlocked every block after `starting_block`. - pub per_block: Balance, - /// Starting block for unlocking(vesting). - pub starting_block: BlockNumber, -} - -impl VestingSchedule { - /// Amount locked at block `n`. - pub fn locked_at(&self, n: BlockNumber) -> Balance - where Balance: From - { - // Number of blocks that count toward vesting - // Saturating to 0 when n < starting_block - let vested_block_count = n.saturating_sub(self.starting_block); - // Return amount that is still locked in vesting - if let Some(x) = Balance::from(vested_block_count).checked_mul(&self.per_block) { - self.locked.max(x) - x - } else { - Zero::zero() - } - } -} - /// Simplified reasons for withdrawing balance. #[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug)] pub enum Reasons { @@ -431,35 +403,6 @@ decl_storage! { config.balances.iter().fold(Zero::zero(), |acc: T::Balance, &(_, n)| acc + n) }): T::Balance; - // TODO: should be in a different pallet and just use the locking system. - - /// Information regarding the vesting of a given account. - pub Vesting get(fn vesting) build(|config: &GenesisConfig| { - // Generate initial vesting configuration - // * who - Account which we are generating vesting configuration for - // * begin - Block when the account will start to vest - // * length - Number of blocks from `begin` until fully vested - // * liquid - Number of units which can be spent before vesting begins - config.vesting.iter().filter_map(|&(ref who, begin, length, liquid)| { - let length = >::from(length); - - config.balances.iter() - .find(|&&(ref w, _)| w == who) - .map(|&(_, balance)| { - // Total genesis `balance` minus `liquid` equals funds locked for vesting - let locked = balance.saturating_sub(liquid); - // Number of units unlocked per block after `begin` - let per_block = locked / length.max(sp_runtime::traits::One::one()); - - (who.clone(), VestingSchedule { - locked: locked, - per_block: per_block, - starting_block: begin - }) - }) - }).collect::>() - }): map T::AccountId => Option>; - /// The balance of an account. pub Balance get(fn balance) build(|config: &GenesisConfig| config.balances.iter() @@ -467,10 +410,8 @@ decl_storage! { .collect::>() ): map T::AccountId => Account; - // TODO: amalgamate the next two into a single item, and also include: - // - fees-locked (min balance to be kept regarding payment of fees - paying a - // fee may not result in the balance being reduced to below this amount) - // - locked (min balance to be kept for any other use) + // TODO: Will need to migrate from old FreeBalance, ReservedBalance and the Locks. + // TODO: Will need to migrate from Locks. /// Any liquidity locks on some account balances. /// NOTE: Should only be accessed when setting, changing and freeing a lock. @@ -483,7 +424,6 @@ decl_storage! { } add_extra_genesis { config(balances): Vec<(T::AccountId, T::Balance)>; - config(vesting): Vec<(T::AccountId, T::BlockNumber, T::BlockNumber, T::Balance)>; // ^^ begin, length, amount liquid at genesis build(|config: &GenesisConfig| { for (_, balance) in &config.balances { @@ -1070,20 +1010,9 @@ where new_balance: T::Balance, ) -> DispatchResult { if amount.is_zero() { return Ok(()) } - - // TODO: remove once there's a vesting pallet. - if reasons.intersects(WithdrawReason::Reserve | WithdrawReason::Transfer) - && Self::vesting_balance(who) > new_balance - { - Err(Error::::VestingBalance)? - } - - let reasons = reasons.into(); - if new_balance >= Balance::::get(who).frozen(reasons) { - Ok(()) - } else { - Err(Error::::LiquidityRestrictions.into()) - } + let min_balance = Balance::::get(who).frozen(reasons.into()); + ensure!(new_balance >= min_balance, Error::::LiquidityRestrictions); + Ok(()) } // Transfer some free balance from `transactor` to `dest`, respecting existence requirements. @@ -1441,52 +1370,6 @@ where } } -impl, I: Instance> VestingCurrency for Module -where - T::Balance: MaybeSerializeDeserialize + Debug -{ - type Moment = T::BlockNumber; - - /// Get the amount that is currently being vested and cannot be transferred out of this account. - fn vesting_balance(who: &T::AccountId) -> T::Balance { - if let Some(v) = Self::vesting(who) { - Self::free_balance(who) - .min(v.locked_at(>::block_number())) - } else { - Zero::zero() - } - } - - /// Adds a vesting schedule to a given account. - /// - /// If there already exists a vesting schedule for the given account, an `Err` is returned - /// and nothing is updated. - /// Is a no-op if the amount to be vested is zero. - fn add_vesting_schedule( - who: &T::AccountId, - locked: T::Balance, - per_block: T::Balance, - starting_block: T::BlockNumber - ) -> DispatchResult { - if locked.is_zero() { return Ok(()) } - if >::exists(who) { - Err(Error::::ExistingVestingSchedule)? - } - let vesting_schedule = VestingSchedule { - locked, - per_block, - starting_block - }; - >::insert(who, vesting_schedule); - Ok(()) - } - - /// Remove a vesting schedule for a given account. - fn remove_vesting_schedule(who: &T::AccountId) { - >::remove(who); - } -} - impl, I: Instance> IsDeadAccount for Module where T::Balance: MaybeSerializeDeserialize + Debug diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index 02fbd94f98df3..cba8f0f1931d1 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -567,160 +567,6 @@ fn transfer_overflow_isnt_exploitable() { }); } -#[test] -fn check_vesting_status() { - ExtBuilder::default() - .existential_deposit(256) - .monied(true) - .vesting(true) - .build() - .execute_with(|| { - assert_eq!(System::block_number(), 1); - let user1_free_balance = Balances::free_balance(&1); - let user2_free_balance = Balances::free_balance(&2); - let user12_free_balance = Balances::free_balance(&12); - assert_eq!(user1_free_balance, 256 * 10); // Account 1 has free balance - assert_eq!(user2_free_balance, 256 * 20); // Account 2 has free balance - assert_eq!(user12_free_balance, 256 * 10); // Account 12 has free balance - let user1_vesting_schedule = VestingSchedule { - locked: 256 * 5, - per_block: 128, // Vesting over 10 blocks - starting_block: 0, - }; - let user2_vesting_schedule = VestingSchedule { - locked: 256 * 20, - per_block: 256, // Vesting over 20 blocks - starting_block: 10, - }; - let user12_vesting_schedule = VestingSchedule { - locked: 256 * 5, - per_block: 64, // Vesting over 20 blocks - starting_block: 10, - }; - assert_eq!(Balances::vesting(&1), Some(user1_vesting_schedule)); // Account 1 has a vesting schedule - assert_eq!(Balances::vesting(&2), Some(user2_vesting_schedule)); // Account 2 has a vesting schedule - assert_eq!(Balances::vesting(&12), Some(user12_vesting_schedule)); // Account 12 has a vesting schedule - - // Account 1 has only 128 units vested from their illiquid 256 * 5 units at block 1 - assert_eq!(Balances::vesting_balance(&1), 128 * 9); - // Account 2 has their full balance locked - assert_eq!(Balances::vesting_balance(&2), user2_free_balance); - // Account 12 has only their illiquid funds locked - assert_eq!(Balances::vesting_balance(&12), user12_free_balance - 256 * 5); - - System::set_block_number(10); - assert_eq!(System::block_number(), 10); - - // Account 1 has fully vested by block 10 - assert_eq!(Balances::vesting_balance(&1), 0); - // Account 2 has started vesting by block 10 - assert_eq!(Balances::vesting_balance(&2), user2_free_balance); - // Account 12 has started vesting by block 10 - assert_eq!(Balances::vesting_balance(&12), user12_free_balance - 256 * 5); - - System::set_block_number(30); - assert_eq!(System::block_number(), 30); - - assert_eq!(Balances::vesting_balance(&1), 0); // Account 1 is still fully vested, and not negative - assert_eq!(Balances::vesting_balance(&2), 0); // Account 2 has fully vested by block 30 - assert_eq!(Balances::vesting_balance(&12), 0); // Account 2 has fully vested by block 30 - - }); -} - -#[test] -fn unvested_balance_should_not_transfer() { - ExtBuilder::default() - .existential_deposit(10) - .monied(true) - .vesting(true) - .build() - .execute_with(|| { - assert_eq!(System::block_number(), 1); - let user1_free_balance = Balances::free_balance(&1); - assert_eq!(user1_free_balance, 100); // Account 1 has free balance - // Account 1 has only 5 units vested at block 1 (plus 50 unvested) - assert_eq!(Balances::vesting_balance(&1), 45); - assert_noop!( - Balances::transfer(Some(1).into(), 2, 56), - Error::::VestingBalance, - ); // Account 1 cannot send more than vested amount - }); -} - -#[test] -fn vested_balance_should_transfer() { - ExtBuilder::default() - .existential_deposit(10) - .monied(true) - .vesting(true) - .build() - .execute_with(|| { - assert_eq!(System::block_number(), 1); - let user1_free_balance = Balances::free_balance(&1); - assert_eq!(user1_free_balance, 100); // Account 1 has free balance - // Account 1 has only 5 units vested at block 1 (plus 50 unvested) - assert_eq!(Balances::vesting_balance(&1), 45); - assert_ok!(Balances::transfer(Some(1).into(), 2, 55)); - }); -} - -#[test] -fn extra_balance_should_transfer() { - ExtBuilder::default() - .existential_deposit(10) - .monied(true) - .vesting(true) - .build() - .execute_with(|| { - assert_eq!(System::block_number(), 1); - assert_ok!(Balances::transfer(Some(3).into(), 1, 100)); - assert_ok!(Balances::transfer(Some(3).into(), 2, 100)); - - let user1_free_balance = Balances::free_balance(&1); - assert_eq!(user1_free_balance, 200); // Account 1 has 100 more free balance than normal - - let user2_free_balance = Balances::free_balance(&2); - assert_eq!(user2_free_balance, 300); // Account 2 has 100 more free balance than normal - - // Account 1 has only 5 units vested at block 1 (plus 150 unvested) - assert_eq!(Balances::vesting_balance(&1), 45); - assert_ok!(Balances::transfer(Some(1).into(), 3, 155)); // Account 1 can send extra units gained - - // Account 2 has no units vested at block 1, but gained 100 - assert_eq!(Balances::vesting_balance(&2), 200); - assert_ok!(Balances::transfer(Some(2).into(), 3, 100)); // Account 2 can send extra units gained - }); -} - -#[test] -fn liquid_funds_should_transfer_with_delayed_vesting() { - ExtBuilder::default() - .existential_deposit(256) - .monied(true) - .vesting(true) - .build() - .execute_with(|| { - assert_eq!(System::block_number(), 1); - let user12_free_balance = Balances::free_balance(&12); - - assert_eq!(user12_free_balance, 2560); // Account 12 has free balance - // Account 12 has liquid funds - assert_eq!(Balances::vesting_balance(&12), user12_free_balance - 256 * 5); - - // Account 12 has delayed vesting - let user12_vesting_schedule = VestingSchedule { - locked: 256 * 5, - per_block: 64, // Vesting over 20 blocks - starting_block: 10, - }; - assert_eq!(Balances::vesting(&12), Some(user12_vesting_schedule)); - - // Account 12 can still send liquid funds - assert_ok!(Balances::transfer(Some(12).into(), 3, 256 * 5)); - }); -} - #[test] fn burn_must_work() { ExtBuilder::default().monied(true).build().execute_with(|| { diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index bc5ab186c0b13..ade25f18fc814 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -943,7 +943,6 @@ pub struct Config { pub max_value_size: u32, pub contract_account_instantiate_fee: BalanceOf, pub account_create_fee: BalanceOf, - pub transfer_fee: BalanceOf, } impl Config { @@ -955,7 +954,6 @@ impl Config { max_value_size: T::MaxValueSize::get(), contract_account_instantiate_fee: T::ContractFee::get(), account_create_fee: T::CreationFee::get(), - transfer_fee: T::TransferFee::get(), } } } diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index bf68d4a8e269e..1695f014a1eaf 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -610,13 +610,17 @@ pub trait LockableCurrency: Currency { ); } -/// A currency whose accounts can have balances which vest over time. -pub trait VestingCurrency: Currency { +/// A vesting schedule over a currency. This allows a particular currency to have vesting limits +/// applied to it. +pub trait VestingSchedule { /// The quantity used to denote time; usually just a `BlockNumber`. type Moment; + /// The currency that this schedule applies to. + type Currency: Currency; + /// Get the amount that is currently being vested and cannot be transferred out of this account. - fn vesting_balance(who: &AccountId) -> Self::Balance; + fn vesting_balance(who: &AccountId) -> >::Balance; /// Adds a vesting schedule to a given account. /// @@ -624,8 +628,8 @@ pub trait VestingCurrency: Currency { /// and nothing is updated. fn add_vesting_schedule( who: &AccountId, - locked: Self::Balance, - per_block: Self::Balance, + locked: >::Balance, + per_block: >::Balance, starting_block: Self::Moment, ) -> DispatchResult; diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml new file mode 100644 index 0000000000000..cf87f55293d11 --- /dev/null +++ b/frame/vesting/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "pallet-vesting" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +serde = { version = "1.0.101", optional = true } +codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } +enumflags2 = { version = "0.6.2" } +sp-std = { version = "2.0.0", default-features = false, path = "../../primitives/std" } +sp-io = { version = "2.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "2.0.0", default-features = false, path = "../../primitives/runtime" } +frame-support = { version = "2.0.0", default-features = false, path = "../support" } +frame-system = { version = "2.0.0", default-features = false, path = "../system" } + +[dev-dependencies] +sp-core = { version = "2.0.0", path = "../../primitives/core" } +pallet-balances = { version = "2.0.0", path = "../balances" } + +[features] +default = ["std"] +std = [ + "serde", + "codec/std", + "sp-std/std", + "sp-io/std", + "sp-runtime/std", + "frame-support/std", + "frame-system/std", +] diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs new file mode 100644 index 0000000000000..fd909b009507a --- /dev/null +++ b/frame/vesting/src/lib.rs @@ -0,0 +1,506 @@ +// Copyright 2019-2020 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! # Vesting Module +//! +//! - [`vesting::Trait`](./trait.Trait.html) +//! - [`Call`](./enum.Call.html) +//! +//! ## Overview +//! +//! ## Interface +//! +//! ### Dispatchable Functions +//! +//! #### For general users +//! +//! #### For super-users +//! +//! [`Call`]: ./enum.Call.html +//! [`Trait`]: ./trait.Trait.html + +#![cfg_attr(not(feature = "std"), no_std)] + +use sp_std::prelude::*; +use sp_std::fmt::Debug; +use codec::{Encode, Decode}; +use sp_runtime::{DispatchResult, RuntimeDebug, traits::{ + StaticLookup, Zero, SimpleArithmetic, MaybeSerializeDeserialize, Saturating, CheckedConversion, + Convert +}}; +use frame_support::{ + decl_module, decl_event, decl_storage, ensure, decl_error, weights::SimpleDispatchInfo, + traits::{ + Currency, LockableCurrency, VestingSchedule, WithdrawReason, LockIdentifier + } +}; +use frame_system::{self as system, ensure_signed, ensure_root}; + +type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; + +pub trait Trait: frame_system::Trait { + /// The overarching event type. + type Event: From> + Into<::Event>; + + /// The currency trait. + type Currency: Currency + LockableCurrency; + + /// Convert the block number into a balance. + type BlockNumberToBalance: Convert>; +} + +const VESTING_ID: LockIdentifier = *b"vesting "; + +/// Struct to encode the vesting schedule of an individual account. +#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug)] +pub struct VestingInfo { + /// Locked amount at genesis. + pub locked: Balance, + /// Amount that gets unlocked every block after `starting_block`. + pub per_block: Balance, + /// Starting block for unlocking(vesting). + pub starting_block: BlockNumber, +} + +impl< + Balance: SimpleArithmetic + Copy, + BlockNumber: SimpleArithmetic + Copy, +> VestingInfo { + /// Amount locked at block `n`. + pub fn locked_at< + BlockNumberToBalance: Convert + >(&self, n: BlockNumber) -> Balance { + // Number of blocks that count toward vesting + // Saturating to 0 when n < starting_block + let vested_block_count = n.saturating_sub(self.starting_block); + let vested_block_count = BlockNumberToBalance::convert(vested_block_count); + // Return amount that is still locked in vesting + let maybe_balance = vested_block_count.checked_mul(&self.per_block); + if let Some(balance) = maybe_balance { + self.locked.max(balance) - balance + } else { + Zero::zero() + } + } +} + +decl_storage! { + trait Store for Module as Sudo { + /// Information regarding the vesting of a given account. + pub Vesting get(fn vesting): + map T::AccountId => Option, T::BlockNumber>>; + } + add_extra_genesis { + config(vesting): Vec<(T::AccountId, T::BlockNumber, T::BlockNumber, BalanceOf)>; + build(|config: &GenesisConfig| { + // Generate initial vesting configuration + // * who - Account which we are generating vesting configuration for + // * begin - Block when the account will start to vest + // * length - Number of blocks from `begin` until fully vested + // * liquid - Number of units which can be spent before vesting begins + for &(ref who, begin, length, liquid) in config.vesting.iter() { + let balance = T::Currency::free_balance(who); + assert!(!balance.is_zero(), "Currencies must be init'd before vesting"); + // Total genesis `balance` minus `liquid` equals funds locked for vesting + let locked = balance.saturating_sub(liquid); + let length_as_balance = T::BlockNumberToBalance::convert(length); + let per_block = locked / length_as_balance.max(sp_runtime::traits::One::one()); + + Vesting::::insert(who, VestingInfo { + locked: locked, + per_block: per_block, + starting_block: begin + }); + let reasons = WithdrawReason::Transfer | WithdrawReason::Reserve; + T::Currency::set_lock(VESTING_ID, who, locked, reasons); + } + }) + } +} + +decl_event!( + pub enum Event where AccountId = ::AccountId, Balance = BalanceOf { + /// The amount vested has been updated. This could indicate more funds are available. The + /// balance given is the amount which is left unvested (and thus locked). + VestingUpdated(AccountId, Balance), + /// An account (given) has become fully vested. No further vesting can happen. + VestingCompleted(AccountId), + } +); + +decl_error! { + /// Error for the vesting module. + pub enum Error for Module { + /// The account given is not vesting. + NotVesting, + /// An existing vesting schedule already exists for this account that cannot be clobbered. + ExistingVestingSchedule, + } +} + +decl_module! { + // Simple declaration of the `Module` type. Lets the macro know what it's working on. + pub struct Module for enum Call where origin: T::Origin { + type Error = Error; + + fn deposit_event() = default; + + /// Unlock any vested funds of the sender account. + /// + /// Origin must be signed with an account that still has funds to vest. + fn vest(origin) -> DispatchResult { + let who = ensure_signed(origin)?; + Self::unlock_vested(who) + } + + /// Unlock any vested funds of a target account. + /// + /// Origin must be signed with an account that still has funds to vest. + fn vest_other(origin, target: T::AccountId) -> DispatchResult { + ensure_signed(origin)?; + Self::unlock_vested(target) + } + } +} + +impl Module { + fn unlock_vested(who: T::AccountId) -> DispatchResult { + ensure!(Vesting::::exists(&who), Error::::NotVesting); + let unvested = Self::vesting_balance(&who); + if unvested.is_zero() { + T::Currency::remove_lock(VESTING_ID, &who); + Self::deposit_event(RawEvent::VestingCompleted(who)); + } else { + let reasons = WithdrawReason::Transfer | WithdrawReason::Reserve; + T::Currency::set_lock(VESTING_ID, &who, unvested, reasons); + Self::deposit_event(RawEvent::VestingUpdated(who, unvested)); + } + Ok(()) + } +} + +impl VestingSchedule for Module where + BalanceOf: MaybeSerializeDeserialize + Debug +{ + type Moment = T::BlockNumber; + type Currency = T::Currency; + + /// Get the amount that is currently being vested and cannot be transferred out of this account. + fn vesting_balance(who: &T::AccountId) -> BalanceOf { + if let Some(v) = Self::vesting(who) { + let now = >::block_number(); + let locked_now = v.locked_at::(now); + T::Currency::free_balance(who).min(locked_now) + } else { + Zero::zero() + } + } + + /// Adds a vesting schedule to a given account. + /// + /// If there already exists a vesting schedule for the given account, an `Err` is returned + /// and nothing is updated. + /// + /// Is a no-op if the amount to be vested is zero. + fn add_vesting_schedule( + who: &T::AccountId, + locked: BalanceOf, + per_block: BalanceOf, + starting_block: T::BlockNumber + ) -> DispatchResult { + if locked.is_zero() { return Ok(()) } + if >::exists(who) { + Err(Error::::ExistingVestingSchedule)? + } + let vesting_schedule = VestingInfo { + locked, + per_block, + starting_block + }; + >::insert(who, vesting_schedule); + Ok(()) + } + + /// Remove a vesting schedule for a given account. + fn remove_vesting_schedule(who: &T::AccountId) { + >::remove(who); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use std::cell::RefCell; + use sp_runtime::traits::BadOrigin; + use frame_support::{ + assert_ok, assert_noop, impl_outer_origin, parameter_types, weights::Weight, + ord_parameter_types, traits::Get + }; + use sp_core::H256; + use frame_system::EnsureSignedBy; + // The testing primitives are very useful for avoiding having to work with signatures + // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. + use sp_runtime::{ + Perbill, testing::Header, traits::{BlakeTwo256, IdentityLookup, Identity}, + }; + + impl_outer_origin! { + pub enum Origin for Test where system = frame_system {} + } + + // For testing the module, we construct most of a mock runtime. This means + // first constructing a configuration type (`Test`) which `impl`s each of the + // configuration traits of modules we want to use. + #[derive(Clone, Eq, PartialEq)] + pub struct Test; + parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: Weight = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); + } + impl frame_system::Trait for Test { + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Call = (); + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = (); + type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; + type AvailableBlockRatio = AvailableBlockRatio; + type Version = (); + type ModuleToIndex = (); + } + parameter_types! { + pub const CreationFee: u64 = 0; + } + impl pallet_balances::Trait for Test { + type Balance = u64; + type OnFreeBalanceZero = (); + type OnReapAccount = System; + type OnNewAccount = (); + type Event = (); + type TransferPayment = (); + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type CreationFee = CreationFee; + } + impl Trait for Test { + type Event = (); + type Currency = Balances; + type BlockNumberToBalance = Identity; + } + type System = frame_system::Module; + type Balances = pallet_balances::Module; + type Vesting = Module; + + thread_local! { + static EXISTENTIAL_DEPOSIT: RefCell = RefCell::new(0); + } + pub struct ExistentialDeposit; + impl Get for ExistentialDeposit { + fn get() -> u64 { EXISTENTIAL_DEPOSIT.with(|v| *v.borrow()) } + } + + pub struct ExtBuilder { + existential_deposit: u64, + } + impl Default for ExtBuilder { + fn default() -> Self { + Self { + existential_deposit: 1, + } + } + } + impl ExtBuilder { + pub fn existential_deposit(mut self, existential_deposit: u64) -> Self { + self.existential_deposit = existential_deposit; + self + } + pub fn build(self) -> sp_io::TestExternalities { + EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit); + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + pallet_balances::GenesisConfig:: { + balances: vec![ + (1, 10 * self.existential_deposit), + (2, 20 * self.existential_deposit), + (3, 30 * self.existential_deposit), + (4, 40 * self.existential_deposit), + (12, 10 * self.existential_deposit) + ], + }.assimilate_storage(&mut t).unwrap(); + GenesisConfig:: { + vesting: vec![ + (1, 0, 10, 5 * self.existential_deposit), + (2, 10, 20, 0), + (12, 10, 20, 5 * self.existential_deposit) + ], + }.assimilate_storage(&mut t).unwrap(); + t.into() + } + } + + #[test] + fn check_vesting_status() { + ExtBuilder::default() + .existential_deposit(256) + .build() + .execute_with(|| { + assert_eq!(System::block_number(), 1); + let user1_free_balance = Balances::free_balance(&1); + let user2_free_balance = Balances::free_balance(&2); + let user12_free_balance = Balances::free_balance(&12); + assert_eq!(user1_free_balance, 256 * 10); // Account 1 has free balance + assert_eq!(user2_free_balance, 256 * 20); // Account 2 has free balance + assert_eq!(user12_free_balance, 256 * 10); // Account 12 has free balance + let user1_vesting_schedule = VestingInfo { + locked: 256 * 5, + per_block: 128, // Vesting over 10 blocks + starting_block: 0, + }; + let user2_vesting_schedule = VestingInfo { + locked: 256 * 20, + per_block: 256, // Vesting over 20 blocks + starting_block: 10, + }; + let user12_vesting_schedule = VestingInfo { + locked: 256 * 5, + per_block: 64, // Vesting over 20 blocks + starting_block: 10, + }; + assert_eq!(Vesting::vesting(&1), Some(user1_vesting_schedule)); // Account 1 has a vesting schedule + assert_eq!(Vesting::vesting(&2), Some(user2_vesting_schedule)); // Account 2 has a vesting schedule + assert_eq!(Vesting::vesting(&12), Some(user12_vesting_schedule)); // Account 12 has a vesting schedule + + // Account 1 has only 128 units vested from their illiquid 256 * 5 units at block 1 + assert_eq!(Vesting::vesting_balance(&1), 128 * 9); + // Account 2 has their full balance locked + assert_eq!(Vesting::vesting_balance(&2), user2_free_balance); + // Account 12 has only their illiquid funds locked + assert_eq!(Vesting::vesting_balance(&12), user12_free_balance - 256 * 5); + + System::set_block_number(10); + assert_eq!(System::block_number(), 10); + + // Account 1 has fully vested by block 10 + assert_eq!(Vesting::vesting_balance(&1), 0); + // Account 2 has started vesting by block 10 + assert_eq!(Vesting::vesting_balance(&2), user2_free_balance); + // Account 12 has started vesting by block 10 + assert_eq!(Vesting::vesting_balance(&12), user12_free_balance - 256 * 5); + + System::set_block_number(30); + assert_eq!(System::block_number(), 30); + + assert_eq!(Vesting::vesting_balance(&1), 0); // Account 1 is still fully vested, and not negative + assert_eq!(Vesting::vesting_balance(&2), 0); // Account 2 has fully vested by block 30 + assert_eq!(Vesting::vesting_balance(&12), 0); // Account 2 has fully vested by block 30 + + }); + } + + #[test] + fn unvested_balance_should_not_transfer() { + ExtBuilder::default() + .existential_deposit(10) + .build() + .execute_with(|| { + assert_eq!(System::block_number(), 1); + let user1_free_balance = Balances::free_balance(&1); + assert_eq!(user1_free_balance, 100); // Account 1 has free balance + // Account 1 has only 5 units vested at block 1 (plus 50 unvested) + assert_eq!(Vesting::vesting_balance(&1), 45); + assert_noop!( + Balances::transfer(Some(1).into(), 2, 56), + pallet_balances::Error::::LiquidityRestrictions, + ); // Account 1 cannot send more than vested amount + }); + } + + #[test] + fn vested_balance_should_transfer() { + ExtBuilder::default() + .existential_deposit(10) + .build() + .execute_with(|| { + assert_eq!(System::block_number(), 1); + let user1_free_balance = Balances::free_balance(&1); + assert_eq!(user1_free_balance, 100); // Account 1 has free balance + // Account 1 has only 5 units vested at block 1 (plus 50 unvested) + assert_eq!(Vesting::vesting_balance(&1), 45); + assert_ok!(Balances::transfer(Some(1).into(), 2, 55)); + }); + } + + #[test] + fn extra_balance_should_transfer() { + ExtBuilder::default() + .existential_deposit(10) + .build() + .execute_with(|| { + assert_eq!(System::block_number(), 1); + assert_ok!(Balances::transfer(Some(3).into(), 1, 100)); + assert_ok!(Balances::transfer(Some(3).into(), 2, 100)); + + let user1_free_balance = Balances::free_balance(&1); + assert_eq!(user1_free_balance, 200); // Account 1 has 100 more free balance than normal + + let user2_free_balance = Balances::free_balance(&2); + assert_eq!(user2_free_balance, 300); // Account 2 has 100 more free balance than normal + + // Account 1 has only 5 units vested at block 1 (plus 150 unvested) + assert_eq!(Vesting::vesting_balance(&1), 45); + assert_ok!(Balances::transfer(Some(1).into(), 3, 155)); // Account 1 can send extra units gained + + // Account 2 has no units vested at block 1, but gained 100 + assert_eq!(Vesting::vesting_balance(&2), 200); + assert_ok!(Balances::transfer(Some(2).into(), 3, 100)); // Account 2 can send extra units gained + }); + } + + #[test] + fn liquid_funds_should_transfer_with_delayed_vesting() { + ExtBuilder::default() + .existential_deposit(256) + .build() + .execute_with(|| { + assert_eq!(System::block_number(), 1); + let user12_free_balance = Balances::free_balance(&12); + + assert_eq!(user12_free_balance, 2560); // Account 12 has free balance + // Account 12 has liquid funds + assert_eq!(Vesting::vesting_balance(&12), user12_free_balance - 256 * 5); + + // Account 12 has delayed vesting + let user12_vesting_schedule = VestingInfo { + locked: 256 * 5, + per_block: 64, // Vesting over 20 blocks + starting_block: 10, + }; + assert_eq!(Vesting::vesting(&12), Some(user12_vesting_schedule)); + + // Account 12 can still send liquid funds + assert_ok!(Balances::transfer(Some(12).into(), 3, 256 * 5)); + }); + } +} From 878a2b9ad3b7810cd176fe88fbf99061faa6081d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 22 Jan 2020 17:39:14 +0100 Subject: [PATCH 07/29] Fix tests --- frame/balances/src/tests.rs | 1 - frame/contracts/src/lib.rs | 4 ++++ frame/vesting/src/lib.rs | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index cba8f0f1931d1..5bf159197b614 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -599,7 +599,6 @@ fn cannot_set_genesis_value_below_ed() { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); let _ = GenesisConfig:: { balances: vec![(1, 10)], - vesting: vec![], }.assimilate_storage(&mut t).unwrap(); } diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index ade25f18fc814..c6cbf9c102416 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -998,6 +998,9 @@ pub struct Schedule { /// Gas cost per one byte written to the sandbox memory. pub sandbox_data_write_cost: Gas, + /// Cost for a simple balance transfer. + pub transfer_cost: Gas, + /// The maximum number of topics supported by an event. pub max_event_topics: u32, @@ -1036,6 +1039,7 @@ impl Default for Schedule { instantiate_base_cost: 175, sandbox_data_read_cost: 1, sandbox_data_write_cost: 1, + transfer_cost: 100, max_event_topics: 4, max_stack_height: 64 * 1024, max_memory_pages: 16, diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index fd909b009507a..8fcf6bad4ff7e 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -448,6 +448,23 @@ mod tests { assert_eq!(user1_free_balance, 100); // Account 1 has free balance // Account 1 has only 5 units vested at block 1 (plus 50 unvested) assert_eq!(Vesting::vesting_balance(&1), 45); + assert_ok!(Vesting::vest(Some(1).into())); + assert_ok!(Balances::transfer(Some(1).into(), 2, 55)); + }); + } + + #[test] + fn vested_balance_should_transfer_using_vest_other() { + ExtBuilder::default() + .existential_deposit(10) + .build() + .execute_with(|| { + assert_eq!(System::block_number(), 1); + let user1_free_balance = Balances::free_balance(&1); + assert_eq!(user1_free_balance, 100); // Account 1 has free balance + // Account 1 has only 5 units vested at block 1 (plus 50 unvested) + assert_eq!(Vesting::vesting_balance(&1), 45); + assert_ok!(Vesting::vest_other(Some(2).into(), 1)); assert_ok!(Balances::transfer(Some(1).into(), 2, 55)); }); } @@ -470,10 +487,12 @@ mod tests { // Account 1 has only 5 units vested at block 1 (plus 150 unvested) assert_eq!(Vesting::vesting_balance(&1), 45); + assert_ok!(Vesting::vest(Some(1).into())); assert_ok!(Balances::transfer(Some(1).into(), 3, 155)); // Account 1 can send extra units gained // Account 2 has no units vested at block 1, but gained 100 assert_eq!(Vesting::vesting_balance(&2), 200); + assert_ok!(Vesting::vest(Some(2).into())); assert_ok!(Balances::transfer(Some(2).into(), 3, 100)); // Account 2 can send extra units gained }); } From efa0e35a428eaf7ebca3f5557691992f64d0e3e7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 22 Jan 2020 18:01:07 +0100 Subject: [PATCH 08/29] Fixes for vesting. --- bin/node-template/src/chain_spec.rs | 1 - bin/node/cli/src/chain_spec.rs | 1 - bin/node/testing/src/genesis.rs | 1 - frame/balances/src/mock.rs | 15 --------------- frame/contracts/src/exec.rs | 2 +- frame/contracts/src/tests.rs | 1 - frame/democracy/src/lib.rs | 1 - frame/elections-phragmen/src/lib.rs | 1 - frame/elections/src/mock.rs | 1 - frame/executive/src/lib.rs | 2 -- frame/identity/src/lib.rs | 1 - frame/nicks/src/lib.rs | 1 - frame/recovery/src/mock.rs | 1 - frame/scored-pool/src/mock.rs | 1 - frame/society/src/mock.rs | 1 - frame/staking/src/mock.rs | 1 - frame/transaction-payment/src/lib.rs | 1 - frame/treasury/src/lib.rs | 2 -- frame/utility/src/lib.rs | 1 - 19 files changed, 1 insertion(+), 35 deletions(-) diff --git a/bin/node-template/src/chain_spec.rs b/bin/node-template/src/chain_spec.rs index fae9feaf5113b..9556585aaed08 100644 --- a/bin/node-template/src/chain_spec.rs +++ b/bin/node-template/src/chain_spec.rs @@ -128,7 +128,6 @@ fn testnet_genesis(initial_authorities: Vec<(AuraId, GrandpaId)>, }), balances: Some(BalancesConfig { balances: endowed_accounts.iter().cloned().map(|k|(k, 1 << 60)).collect(), - vesting: vec![], }), sudo: Some(SudoConfig { key: root_key, diff --git a/bin/node/cli/src/chain_spec.rs b/bin/node/cli/src/chain_spec.rs index 26b1f6d2949e3..ea501957d02b8 100644 --- a/bin/node/cli/src/chain_spec.rs +++ b/bin/node/cli/src/chain_spec.rs @@ -237,7 +237,6 @@ pub fn testnet_genesis( .map(|k| (k, ENDOWMENT)) .chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH))) .collect(), - vesting: vec![], }), pallet_indices: Some(IndicesConfig { ids: endowed_accounts.iter().cloned() diff --git a/bin/node/testing/src/genesis.rs b/bin/node/testing/src/genesis.rs index 44dd79a7f438a..817a3d2c6622e 100644 --- a/bin/node/testing/src/genesis.rs +++ b/bin/node/testing/src/genesis.rs @@ -49,7 +49,6 @@ pub fn config(support_changes_trie: bool, code: Option<&[u8]>) -> GenesisConfig (eve(), 101 * DOLLARS), (ferdie(), 100 * DOLLARS), ], - vesting: vec![], }), pallet_session: Some(SessionConfig { keys: vec![ diff --git a/frame/balances/src/mock.rs b/frame/balances/src/mock.rs index e16462154f936..f4b932e192a05 100644 --- a/frame/balances/src/mock.rs +++ b/frame/balances/src/mock.rs @@ -100,7 +100,6 @@ pub struct ExtBuilder { existential_deposit: u64, creation_fee: u64, monied: bool, - vesting: bool, } impl Default for ExtBuilder { fn default() -> Self { @@ -108,7 +107,6 @@ impl Default for ExtBuilder { existential_deposit: 0, creation_fee: 0, monied: false, - vesting: false, } } } @@ -128,10 +126,6 @@ impl ExtBuilder { } self } - pub fn vesting(mut self, vesting: bool) -> Self { - self.vesting = vesting; - self - } pub fn set_associated_consts(&self) { EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit); CREATION_FEE.with(|v| *v.borrow_mut() = self.creation_fee); @@ -151,15 +145,6 @@ impl ExtBuilder { } else { vec![] }, - vesting: if self.vesting && self.monied { - vec![ - (1, 0, 10, 5 * self.existential_deposit), - (2, 10, 20, 0), - (12, 10, 20, 5 * self.existential_deposit) - ] - } else { - vec![] - }, }.assimilate_storage(&mut t).unwrap(); t.into() } diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 2c77173135077..845f47567bee5 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -570,7 +570,7 @@ impl Token for TransferFeeToken> { let balance_fee = match self.kind { TransferFeeKind::ContractInstantiate => metadata.contract_account_instantiate_fee, TransferFeeKind::AccountCreate => metadata.account_create_fee, - TransferFeeKind::Transfer => metadata.transfer_fee, + TransferFeeKind::Transfer => return metadata.schedule.transfer_cost, }; approx_gas_for_balance(self.gas_price, balance_fee) } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index f24478445d705..01bcdf8156c78 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -276,7 +276,6 @@ impl ExtBuilder { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); pallet_balances::GenesisConfig:: { balances: vec![], - vesting: vec![], }.assimilate_storage(&mut t).unwrap(); GenesisConfig:: { current_schedule: Schedule { diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 6b4569d7ca4d6..def9cad0d17d3 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -1287,7 +1287,6 @@ mod tests { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); pallet_balances::GenesisConfig::{ balances: vec![(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)], - vesting: vec![], }.assimilate_storage(&mut t).unwrap(); GenesisConfig::default().assimilate_storage(&mut t).unwrap(); sp_io::TestExternalities::new(t) diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 85f86fe771cb4..4da0de23e3f32 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -986,7 +986,6 @@ mod tests { (5, 50 * self.balance_factor), (6, 60 * self.balance_factor) ], - vesting: vec![], }), }.build_storage().unwrap().into() } diff --git a/frame/elections/src/mock.rs b/frame/elections/src/mock.rs index 569e169beffff..87a660bc3f180 100644 --- a/frame/elections/src/mock.rs +++ b/frame/elections/src/mock.rs @@ -220,7 +220,6 @@ impl ExtBuilder { (5, 50 * self.balance_factor), (6, 60 * self.balance_factor) ], - vesting: vec![], }), elections: Some(elections::GenesisConfig::{ members: vec![], diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 54070f325c75b..634cb54696284 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -527,7 +527,6 @@ mod tests { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); pallet_balances::GenesisConfig:: { balances: vec![(1, 211)], - vesting: vec![], }.assimilate_storage(&mut t).unwrap(); let xt = sp_runtime::testing::TestXt(sign_extra(1, 0, 0), Call::Balances(BalancesCall::transfer(2, 69))); let weight = xt.get_dispatch_info().weight as u64; @@ -551,7 +550,6 @@ mod tests { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); pallet_balances::GenesisConfig:: { balances: vec![(1, 111 * balance_factor)], - vesting: vec![], }.assimilate_storage(&mut t).unwrap(); t.into() } diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index 496c476faae28..ecd5ca92580c3 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -966,7 +966,6 @@ mod tests { (20, 100), (30, 100), ], - vesting: vec![], }.assimilate_storage(&mut t).unwrap(); t.into() } diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index 145ea2cc1a7d2..2d816e4a55bc2 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -332,7 +332,6 @@ mod tests { (1, 10), (2, 10), ], - vesting: vec![], }.assimilate_storage(&mut t).unwrap(); t.into() } diff --git a/frame/recovery/src/mock.rs b/frame/recovery/src/mock.rs index 1da1d334aa582..24ca9ff9d6d50 100644 --- a/frame/recovery/src/mock.rs +++ b/frame/recovery/src/mock.rs @@ -124,7 +124,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); pallet_balances::GenesisConfig:: { balances: vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100)], - vesting: vec![], }.assimilate_storage(&mut t).unwrap(); t.into() } diff --git a/frame/scored-pool/src/mock.rs b/frame/scored-pool/src/mock.rs index d22f0aa572ca1..e55869fc74f00 100644 --- a/frame/scored-pool/src/mock.rs +++ b/frame/scored-pool/src/mock.rs @@ -142,7 +142,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities { (40, 500_000), (99, 1), ], - vesting: vec![], }.assimilate_storage(&mut t).unwrap(); GenesisConfig::{ pool: vec![ diff --git a/frame/society/src/mock.rs b/frame/society/src/mock.rs index e61402c671bff..f3bb730ef92e3 100644 --- a/frame/society/src/mock.rs +++ b/frame/society/src/mock.rs @@ -145,7 +145,6 @@ impl EnvBuilder { self.balances.push((Society::account_id(), self.balance.max(self.pot))); pallet_balances::GenesisConfig:: { balances: self.balances, - vesting: vec![], }.assimilate_storage(&mut t).unwrap(); GenesisConfig::{ members: self.members, diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 0530eb55922bf..296a00d0f5af3 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -322,7 +322,6 @@ impl ExtBuilder { // This allow us to have a total_payout different from 0. (999, 1_000_000_000_000), ], - vesting: vec![], }.assimilate_storage(&mut storage); let stake_21 = if self.fair { 1000 } else { 2000 }; diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 7aa5c7dd0176f..6fd26a18ec1ee 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -404,7 +404,6 @@ mod tests { (5, 50 * self.balance_factor), (6, 60 * self.balance_factor) ], - vesting: vec![], }.assimilate_storage(&mut t).unwrap(); t.into() } diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index e098484f5b088..8eb84d339cc9e 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -816,7 +816,6 @@ mod tests { pallet_balances::GenesisConfig::{ // Total issuance will be 200 with treasury account initialized at ED. balances: vec![(0, 100), (1, 98), (2, 1)], - vesting: vec![], }.assimilate_storage(&mut t).unwrap(); GenesisConfig::default().assimilate_storage::(&mut t).unwrap(); t.into() @@ -1142,7 +1141,6 @@ mod tests { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); pallet_balances::GenesisConfig::{ balances: vec![(0, 100), (1, 99), (2, 1)], - vesting: vec![], }.assimilate_storage(&mut t).unwrap(); // Treasury genesis config is not build thus treasury account does not exist let mut t: sp_io::TestExternalities = t.into(); diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index a8423551b7907..9bca741fea8bd 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -738,7 +738,6 @@ mod tests { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); pallet_balances::GenesisConfig:: { balances: vec![(1, 10), (2, 10), (3, 10), (4, 10), (5, 10)], - vesting: vec![], }.assimilate_storage(&mut t).unwrap(); t.into() } From 9f47c3233f182571f69f06badfd40f5920f43716 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 23 Jan 2020 12:46:51 +0100 Subject: [PATCH 09/29] Docs. --- frame/balances/src/lib.rs | 6 ------ frame/vesting/src/lib.rs | 38 ++++++++++++++++++++++++-------------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index b63d296ee8811..081fd244fb67e 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -67,8 +67,6 @@ //! simply dropped, it should automatically maintain any book-keeping such as total issuance.) //! - **Lock:** A freeze on a specified amount of an account's free balance until a specified block number. Multiple //! locks always operate over the same funds, so they "overlay" rather than "stack". -//! - **Vesting:** Similar to a lock, this is another, but independent, liquidity restriction that reduces linearly -//! over time. //! //! ### Implementations //! @@ -94,10 +92,6 @@ //! - `transfer` - Transfer some liquid free balance to another account. //! - `set_balance` - Set the balances of a given account. The origin of this call must be root. //! -//! ### Public Functions -//! -//! - `vesting_balance` - Get the amount that is currently being vested and cannot be transferred out of this account. -//! //! ## Usage //! //! The following examples show how to use the Balances module in your custom module. diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 8fcf6bad4ff7e..b1d0d472a02b3 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -21,13 +21,25 @@ //! //! ## Overview //! +//! A simple module providing a means of placing a linear curve on an account's locked balance. This +//! module ensures that there is a lock in place preventing the balance to drop below the *unvested* +//! amount for any reason other than transaction fee payment. +//! +//! As the amount vested increases over time, the amount unvested reduces. However, locks remain in +//! place and explicit action is needed on behalf of the user to ensure that the amount locked is +//! equivalent to the amount remaining to be vested. This is done through a dispatchable function, +//! either `vest` (in typical case where the sender is calling on their own behalf) or `vest_other` +//! in case the sender is calling on another account's behalf. +//! //! ## Interface //! -//! ### Dispatchable Functions +//! This module implements the `VestingSchedule` trait. //! -//! #### For general users +//! ### Dispatchable Functions //! -//! #### For super-users +//! - `vest` - Update the lock, reducing it in line with the amount "vested" so far. +//! - `vest_other` - Update the lock of another account, reducing it in line with the amount +//! "vested" so far. //! //! [`Call`]: ./enum.Call.html //! [`Trait`]: ./trait.Trait.html @@ -38,16 +50,12 @@ use sp_std::prelude::*; use sp_std::fmt::Debug; use codec::{Encode, Decode}; use sp_runtime::{DispatchResult, RuntimeDebug, traits::{ - StaticLookup, Zero, SimpleArithmetic, MaybeSerializeDeserialize, Saturating, CheckedConversion, - Convert + StaticLookup, Zero, SimpleArithmetic, MaybeSerializeDeserialize, Saturating, Convert }}; -use frame_support::{ - decl_module, decl_event, decl_storage, ensure, decl_error, weights::SimpleDispatchInfo, - traits::{ - Currency, LockableCurrency, VestingSchedule, WithdrawReason, LockIdentifier - } -}; -use frame_system::{self as system, ensure_signed, ensure_root}; +use frame_support::{decl_module, decl_event, decl_storage, ensure, decl_error, traits::{ + Currency, LockableCurrency, VestingSchedule, WithdrawReason, LockIdentifier +}}; +use frame_system::{self as system, ensure_signed}; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -169,14 +177,16 @@ decl_module! { /// Unlock any vested funds of a target account. /// /// Origin must be signed with an account that still has funds to vest. - fn vest_other(origin, target: T::AccountId) -> DispatchResult { + fn vest_other(origin, target: ::Source) -> DispatchResult { ensure_signed(origin)?; - Self::unlock_vested(target) + Self::unlock_vested(T::Lookup::lookup(target)?) } } } impl Module { + /// (Re)set or remove the module's currency lock on `who`'s account in accordance with their + /// current unvested amount. fn unlock_vested(who: T::AccountId) -> DispatchResult { ensure!(Vesting::::exists(&who), Error::::NotVesting); let unvested = Self::vesting_balance(&who); From 370bdbe3209cda7517a277a355366687e54127d8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 23 Jan 2020 12:53:05 +0100 Subject: [PATCH 10/29] Weight docs. --- frame/vesting/src/lib.rs | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index b1d0d472a02b3..560ef19080960 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -168,15 +168,38 @@ decl_module! { /// Unlock any vested funds of the sender account. /// - /// Origin must be signed with an account that still has funds to vest. + /// The dispatch origin for this call must be _Signed_ and the sender must have funds still + /// locked under this module. + /// + /// Emits either `VestingCompleted` or `VestingUpdated`. + /// + /// # + /// - `O(1)`. + /// - One balance-lock operation. + /// - One storage read (codec `O(1)`) and up to one removal. + /// - One event. + /// # fn vest(origin) -> DispatchResult { let who = ensure_signed(origin)?; Self::unlock_vested(who) } - /// Unlock any vested funds of a target account. + /// Unlock any vested funds of a `target` account. + /// + /// The dispatch origin for this call must be _Signed_. + /// + /// - `target`: The account whose vested funds should be unlocked. Must have funds still + /// locked under this module. + /// + /// Emits either `VestingCompleted` or `VestingUpdated`. /// - /// Origin must be signed with an account that still has funds to vest. + /// # + /// - `O(1)`. + /// - Up to one account lookup. + /// - One balance-lock operation. + /// - One storage read (codec `O(1)`) and up to one removal. + /// - One event. + /// # fn vest_other(origin, target: ::Source) -> DispatchResult { ensure_signed(origin)?; Self::unlock_vested(T::Lookup::lookup(target)?) @@ -192,6 +215,7 @@ impl Module { let unvested = Self::vesting_balance(&who); if unvested.is_zero() { T::Currency::remove_lock(VESTING_ID, &who); + Vesting::::kill(&who); Self::deposit_event(RawEvent::VestingCompleted(who)); } else { let reasons = WithdrawReason::Transfer | WithdrawReason::Reserve; From fb4e7937540aaa76fa0bb0f8e1207c76a1324fea Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 23 Jan 2020 14:59:44 +0100 Subject: [PATCH 11/29] Refactor things in terms of set_balances. --- frame/balances/src/lib.rs | 404 ++++++++++++++++-------------------- frame/balances/src/tests.rs | 3 +- frame/support/src/traits.rs | 2 + 3 files changed, 186 insertions(+), 223 deletions(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 081fd244fb67e..0d99395b055d2 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -398,6 +398,9 @@ decl_storage! { }): T::Balance; /// The balance of an account. + /// + /// NOTE: THIS MAY NEVER BE IN EXISTENCE AND YET HAVE A `total().is_zero()`. If the total + /// is ever zero, then the entry *MUST* be removed. pub Balance get(fn balance) build(|config: &GenesisConfig| config.balances.iter() .map(|&(ref who, free)| (who.clone(), Account { free, .. Default::default() })) @@ -563,52 +566,11 @@ decl_module! { impl, I: Instance> Module { // PRIVATE MUTABLES - /// Set the reserved balance of an account to some new value. Will enforce `ExistentialDeposit` - /// law, annulling the account as needed. - /// - /// Doesn't do any preparatory work for creating a new account, so should only be used when it - /// is known that the account already exists. - /// - /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that - /// the caller will do this. - fn set_reserved_balance(who: &T::AccountId, balance: T::Balance) -> UpdateBalanceOutcome { - Balance::::mutate(who, |b| b.reserved = balance); - if balance < T::ExistentialDeposit::get() { - Self::on_reserved_too_low(who) - } else { - UpdateBalanceOutcome::Updated - } - } - - /// Set the free balance of an account to some new value. Will enforce `ExistentialDeposit` - /// law, annulling the account as needed. - /// - /// Doesn't do any preparatory work for creating a new account, so should only be used when it - /// is known that the account already exists. - /// - /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that - /// the caller will do this. - fn set_free_balance(who: &T::AccountId, balance: T::Balance) -> UpdateBalanceOutcome { - // Commented out for now - but consider it instructive. - // assert!(!Self::total_balance(who).is_zero()); - // assert!(Self::free_balance(who) > T::ExistentialDeposit::get()); - Balance::::mutate(who, |b| b.free = balance); - if balance < T::ExistentialDeposit::get() { - Self::on_free_too_low(who) - } else { - UpdateBalanceOutcome::Updated - } - } - /// Set both the free and reserved balance of an account to some new value. Will enforce /// `ExistentialDeposit` law, annulling the account as needed. /// /// Will return `AccountKilled` if either reserved or free are too low. /// - /// This is generally faster than calling `set_free_balance` or `set_reserved_balance` since - /// it avoids the need for a storage `get`. It should be used in preference when an up-to-date - /// `Account` value is available. - /// /// NOTE: This assumes that `account` is the same as `Self::balance(who)` except for altered /// values of `free` and `balance`. /// @@ -617,17 +579,55 @@ impl, I: Instance> Module { /// /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that /// the caller will do this. - fn set_balances(who: &T::AccountId, account: &Account) -> UpdateBalanceOutcome { + fn set_balances( + who: &T::AccountId, + mut account: Account, + old: Account, + ) -> UpdateBalanceOutcome { + println!("Setting balance of {:?} to {:?} from {:?}", who, account, Self::balance(who)); // Commented out for now - but consider it instructive. // assert!(!Self::total_balance(who).is_zero()); // assert!(Self::free_balance(who) > T::ExistentialDeposit::get()); - Balance::::insert(who, account); - if account.free < T::ExistentialDeposit::get() { - Self::on_free_too_low(who) - } else if account.reserved < T::ExistentialDeposit::get() { - Self::on_reserved_too_low(who) + let mut outcome = UpdateBalanceOutcome::Updated; + + let ed = T::ExistentialDeposit::get(); + if account.free < ed { + account.reserved += account.free; + account.free = Zero::zero(); + if old.free >= ed { + T::OnFreeBalanceZero::on_free_balance_zero(who); + outcome = UpdateBalanceOutcome::FreeBalanceZero; + } + } + let mut dust = Zero::zero(); + if account.reserved < ed { + if account.free >= ed { + account.free += account.reserved; + } else { + dust = account.reserved; + } + account.reserved = Zero::zero(); + if old.reserved >= ed { + outcome = UpdateBalanceOutcome::ReservedBalanceZero; + } + } + if !dust.is_zero() { + T::DustRemoval::on_unbalanced(NegativeImbalance::new(dust)); + } + + if account.total().is_zero() { + if !old.total().is_zero() { + Self::reap_account(who, dust); + UpdateBalanceOutcome::AccountKilled + } else { + UpdateBalanceOutcome::StillDead + } } else { - UpdateBalanceOutcome::Updated + if old.total().is_zero() { + Self::about_to_create_account(who, account.free); + } + Balance::::insert(who, account); + outcome } } @@ -649,67 +649,6 @@ impl, I: Instance> Module { Self::deposit_event(RawEvent::ReapedAccount(who.clone(), dust)); } - /// Account's free balance has dropped below existential deposit. Kill its - /// free side and the account completely if its reserved size is already dead. - /// - /// Will maintain total issuance. - fn on_free_too_low(who: &T::AccountId) -> UpdateBalanceOutcome { - let mut b = Balance::::get(who); - let mut dust = Zero::zero(); - if !b.free.is_zero() { - if b.reserved >= T::ExistentialDeposit::get() { - // any individual account cannot cause overflow in balance. - b.reserved += b.free; - } else { - // underflow should never happen, but if it does, there's not much we can do. - dust = b.free + b.reserved; - T::DustRemoval::on_unbalanced(NegativeImbalance::new(dust)); - b.reserved = Zero::zero(); - } - b.free = Zero::zero(); - } - Balance::::insert(who, &b); - - T::OnFreeBalanceZero::on_free_balance_zero(who); - - if b.reserved.is_zero() { - Self::reap_account(who, dust); - UpdateBalanceOutcome::AccountKilled - } else { - UpdateBalanceOutcome::FreeBalanceZero - } - } - - /// Account's reserved balance has dropped below existential deposit. Kill its - /// reserved side and the account completely if its free size is already dead. - /// - /// Will maintain total issuance. - fn on_reserved_too_low(who: &T::AccountId) -> UpdateBalanceOutcome { - let mut b = Balance::::get(who); - let mut dust = Zero::zero(); - - if !b.reserved.is_zero() { - if b.free >= T::ExistentialDeposit::get() { - // any individual account cannot cause overflow in balance. - b.free += b.reserved; - } else { - // underflow should never happen, but if it does, there's not much we can do. - dust = b.free + b.reserved; - T::DustRemoval::on_unbalanced(NegativeImbalance::new(dust)); - b.free = Zero::zero(); - } - b.reserved = Zero::zero(); - } - Balance::::insert(who, &b); - - if b.free.is_zero() { - Self::reap_account(who, dust); - UpdateBalanceOutcome::AccountKilled - } else { - UpdateBalanceOutcome::ReservedBalanceZero - } - } - /// Update the account entry for `who`, given the locks. fn update_locks(who: &T::AccountId, locks: &[BalanceLock]) { Balance::::mutate(who, |b| { @@ -932,8 +871,7 @@ impl, I: Instance> Trait for ElevatedTrait { type CreationFee = T::CreationFee; } -impl, I: Instance> Currency for Module -where +impl, I: Instance> Currency for Module where T::Balance: MaybeSerializeDeserialize + Debug { type Balance = T::Balance; @@ -1019,8 +957,10 @@ where ) -> DispatchResult { if value.is_zero() || transactor == dest { return Ok(()) } - let mut from_balance = Self::balance(transactor); - let mut to_balance = Self::balance(dest); + let old_from_balance = Self::balance(transactor); + let mut from_balance = old_from_balance.clone(); + let old_to_balance = Self::balance(dest); + let mut to_balance = old_to_balance.clone(); let would_create = to_balance.total().is_zero(); let fee = if would_create { T::CreationFee::get() } else { Zero::zero() }; @@ -1046,17 +986,14 @@ where let allow_death = existence_requirement == ExistenceRequirement::AllowDeath; ensure!(allow_death || from_balance.free >= ed, Error::::KeepAlive); - Self::set_balances(transactor, &from_balance); + Self::set_balances(transactor, from_balance, old_from_balance); // Emit transfer event. Self::deposit_event(RawEvent::Transfer(transactor.clone(), dest.clone(), value, fee)); - if would_create { - Self::about_to_create_account(dest, to_balance.free); - } - // Take action on the set_free_balance call. + // Take action on the set_balances call. // This will emit events that _resulted_ from the transfer. - Self::set_balances(dest, &to_balance); + Self::set_balances(dest, to_balance, old_to_balance); T::TransferPayment::on_unbalanced(NegativeImbalance::new(fee)); @@ -1073,105 +1010,122 @@ where ) -> result::Result { if value.is_zero() { return Ok(NegativeImbalance::zero()); } - // TODO: rewrite using composite balance. - - let old_balance = Self::free_balance(who); - if let Some(new_balance) = old_balance.checked_sub(&value) { + let old_balance = Self::balance(who); + let mut balance = old_balance.clone(); + if let Some(new_free_balance) = balance.free.checked_sub(&value) { // if we need to keep the account alive... if liveness == ExistenceRequirement::KeepAlive // ...and it would be dead afterwards... - && new_balance < T::ExistentialDeposit::get() + && new_free_balance < T::ExistentialDeposit::get() // ...yet is was alive before - && old_balance >= T::ExistentialDeposit::get() + && balance.free >= T::ExistentialDeposit::get() { Err(Error::::KeepAlive)? } - Self::ensure_can_withdraw(who, value, reasons, new_balance)?; - Self::set_free_balance(who, new_balance); + Self::ensure_can_withdraw(who, value, reasons, new_free_balance)?; + balance.free = new_free_balance; + Self::set_balances(who, balance, old_balance); Ok(NegativeImbalance::new(value)) } else { Err(Error::::InsufficientBalance)? } } - // Slash an account, returning the negative imbalance created and any left over - // amount that could not be slashed. - // Is a no-op if value to be slashed is zero. + /// Slash a target account `who`, returning the negative imbalance created and any left over + /// amount that could not be slashed. + /// + /// Is a no-op if `value` to be slashed is zero. + /// + /// NOTE: `slash()` prefers free balance, but assumes that reserve balance can be drawn + /// from in extreme circumstances. `can_slash()` should be used prior to `slash()` to avoid having + /// to draw from reserved funds, however we err on the side of punishment if things are inconsistent + /// or `can_slash` wasn't used appropriately. fn slash( who: &T::AccountId, value: Self::Balance ) -> (Self::NegativeImbalance, Self::Balance) { if value.is_zero() { return (NegativeImbalance::zero(), Zero::zero()) } - // TODO: rewrite using composite balance. + let old_balance = Self::balance(who); + let mut balance = old_balance.clone(); - let free_balance = Self::free_balance(who); - let free_slash = cmp::min(free_balance, value); + let free_slash = cmp::min(balance.free, value); + balance.free -= free_slash; - Self::set_free_balance(who, free_balance - free_slash); let remaining_slash = value - free_slash; - // NOTE: `slash()` prefers free balance, but assumes that reserve balance can be drawn - // from in extreme circumstances. `can_slash()` should be used prior to `slash()` to avoid having - // to draw from reserved funds, however we err on the side of punishment if things are inconsistent - // or `can_slash` wasn't used appropriately. - if !remaining_slash.is_zero() { - let reserved_balance = Self::reserved_balance(who); - let reserved_slash = cmp::min(reserved_balance, remaining_slash); - Self::set_reserved_balance(who, reserved_balance - reserved_slash); + let result = if !remaining_slash.is_zero() { + let reserved_slash = cmp::min(balance.reserved, remaining_slash); + balance.reserved -= reserved_slash; (NegativeImbalance::new(free_slash + reserved_slash), remaining_slash - reserved_slash) } else { (NegativeImbalance::new(value), Zero::zero()) - } + }; + Self::set_balances(who, balance, old_balance); + result } - // Deposit some `value` into the free balance of an existing account. - // Is a no-op if the value to be deposited is zero. + /// Deposit some `value` into the free balance of an existing target account `who`. + /// + /// Is a no-op if the `value` to be deposited is zero. fn deposit_into_existing( who: &T::AccountId, value: Self::Balance ) -> result::Result { if value.is_zero() { return Ok(PositiveImbalance::zero()) } - // TODO: rewrite using composite balance. + let old_balance = Self::balance(who); + let mut balance = old_balance.clone(); + ensure!(!balance.total().is_zero(), Error::::DeadAccount); + balance.free = balance.free.checked_add(&value).ok_or(Error::::Overflow)?; - if Self::total_balance(who).is_zero() { - Err(Error::::DeadAccount)? - } - Self::set_free_balance(who, Self::free_balance(who) + value); + Self::set_balances(who, balance, old_balance); Ok(PositiveImbalance::new(value)) } - // Deposit some `value` into the free balance of `who`, possibly creating a new account. - // Is a no-op if the value to be deposited is zero. + /// Deposit some `value` into the free balance of `who`, possibly creating a new account. + /// + /// This function is a no-op if: + /// - the `value` to be deposited is zero; or + /// - if the `value` to be deposited is less than the ED and the account does not yet exist; or + /// - `value` is so large it would cause the balance of `who` to overflow. fn deposit_creating( who: &T::AccountId, value: Self::Balance, ) -> Self::PositiveImbalance { if value.is_zero() { return Self::PositiveImbalance::zero() } - // TODO: rewrite using composite balance. + let old_balance = Self::balance(who); + let mut balance = old_balance.clone(); + let ed = T::ExistentialDeposit::get(); + + // bail if not yet created and this operation wouldn't be enough to create it. + if value < ed && balance.total().is_zero() { return Self::PositiveImbalance::zero() } - let (imbalance, _) = Self::make_free_balance_be(who, Self::free_balance(who) + value); - if let SignedImbalance::Positive(p) = imbalance { - p - } else { - // Impossible, but be defensive. - Self::PositiveImbalance::zero() - } + // defensive only: overflow should never happen, however in case it does, then this + // operation is a no-op. + balance.free = match balance.free.checked_add(&value) { + Some(f) => f, + None => return Self::PositiveImbalance::zero(), + }; + + Self::set_balances(who, balance, old_balance); + + PositiveImbalance::new(value) } - fn make_free_balance_be(who: &T::AccountId, balance: Self::Balance) -> ( + /// Force the new free balance of a target account `who` to some new value `balance`. + fn make_free_balance_be(who: &T::AccountId, value: Self::Balance) -> ( SignedImbalance, UpdateBalanceOutcome ) { - // TODO: rewrite using composite balance. + let old_balance = Self::balance(who); + let mut balance = old_balance.clone(); - let original = Self::free_balance(who); - if balance < T::ExistentialDeposit::get() && original.is_zero() { + if value < T::ExistentialDeposit::get() && balance.free.is_zero() { // If we're attempting to set an existing account to less than ED, then // bypass the entire operation. It's a no-op if you follow it through, but // since this is an instance where we might account for a negative imbalance - // (in the dust cleaner of set_free_balance) before we account for its actual + // (in the dust cleaner of set_balances) before we account for its actual // equal and opposite cause (returned as an Imbalance), then in the // instance that there's no other accounts on the system at all, we might // underflow the issuance and our arithmetic will be off. @@ -1180,29 +1134,18 @@ where UpdateBalanceOutcome::AccountKilled, ) } - let imbalance = if original <= balance { - SignedImbalance::Positive(PositiveImbalance::new(balance - original)) + let imbalance = if balance.free <= value { + SignedImbalance::Positive(PositiveImbalance::new(value - balance.free)) } else { - SignedImbalance::Negative(NegativeImbalance::new(original - balance)) + SignedImbalance::Negative(NegativeImbalance::new(balance.free - value)) }; + balance.free = value; + // If the balance is too low, then the account is reaped. - // NOTE: There are two balances for every account: `reserved_balance` and - // `free_balance`. This contract subsystem only cares about the latter: whenever - // the term "balance" is used *here* it should be assumed to mean "free balance" - // in the rest of the module. // Free balance can never be less than ED. If that happens, it gets reduced to zero // and the account information relevant to this subsystem is deleted (i.e. the // account is reaped). - let outcome = if balance < T::ExistentialDeposit::get() { - Self::set_free_balance(who, balance); - UpdateBalanceOutcome::AccountKilled - } else { - if !Balance::::exists(who) { - Self::about_to_create_account(&who, balance); - } - Self::set_free_balance(who, balance); - UpdateBalanceOutcome::Updated - }; + let outcome = Self::set_balances(who, balance, old_balance); (imbalance, outcome) } } @@ -1211,8 +1154,9 @@ impl, I: Instance> ReservableCurrency for Module where T::Balance: MaybeSerializeDeserialize + Debug { - // Check if `who` can reserve `value` from their free balance. - // Is a no-op if value to be reserved is zero. + /// Check if `who` can reserve `value` from their free balance. + /// + /// Always `true` if value to be reserved is zero. fn can_reserve(who: &T::AccountId, value: Self::Balance) -> bool { if value.is_zero() { return true } Self::free_balance(who) @@ -1223,61 +1167,71 @@ where } fn reserved_balance(who: &T::AccountId) -> Self::Balance { - Balance::::get(who).reserved + Self::balance(who).reserved } - // Move `value` from the free balance from `who` to their reserved balance. - // Is a no-op if value to be reserved is zero. + /// Move `value` from the free balance from `who` to their reserved balance. + /// + /// Is a no-op if value to be reserved is zero. fn reserve(who: &T::AccountId, value: Self::Balance) -> result::Result<(), DispatchError> { if value.is_zero() { return Ok(()) } - // TODO: rewrite using composite balance. + let old_balance = Self::balance(who); + let mut balance = old_balance.clone(); - let b = Self::free_balance(who); - if b < value { - Err(Error::::InsufficientBalance)? - } - let new_balance = b - value; - Self::ensure_can_withdraw(who, value, WithdrawReason::Reserve.into(), new_balance)?; - Self::set_reserved_balance(who, Self::reserved_balance(who) + value); - Self::set_free_balance(who, new_balance); + balance.free = balance.free.checked_sub(&value).ok_or(Error::::InsufficientBalance)?; + balance.reserved = balance.reserved.checked_add(&value).ok_or(Error::::Overflow)?; + Self::ensure_can_withdraw(who, value, WithdrawReason::Reserve.into(), balance.free)?; + + Self::set_balances(who, balance, old_balance); Ok(()) } - // Unreserve some funds, returning any amount that was unable to be unreserved. - // Is a no-op if the value to be unreserved is zero. + /// Unreserve some funds, returning any amount that was unable to be unreserved. + /// + /// Is a no-op if the value to be unreserved is zero. fn unreserve(who: &T::AccountId, value: Self::Balance) -> Self::Balance { if value.is_zero() { return Zero::zero() } - // TODO: rewrite using composite balance. + let old_balance = Self::balance(who); + let mut balance = old_balance.clone(); + + let actual = cmp::min(balance.reserved, value); + balance.reserved -= actual; + // defensive only: this can never fail since total issuance which is at least free+reservred + // fits into the same datatype. + balance.free = balance.free.saturating_add(actual); + + Self::set_balances(who, balance, old_balance); - let b = Self::reserved_balance(who); - let actual = cmp::min(b, value); - Self::set_free_balance(who, Self::free_balance(who) + actual); - Self::set_reserved_balance(who, b - actual); value - actual } - // Slash from reserved balance, returning the negative imbalance created, - // and any amount that was unable to be slashed. - // Is a no-op if the value to be slashed is zero. + /// Slash from reserved balance, returning the negative imbalance created, + /// and any amount that was unable to be slashed. + /// + /// Is a no-op if the value to be slashed is zero. fn slash_reserved( who: &T::AccountId, value: Self::Balance ) -> (Self::NegativeImbalance, Self::Balance) { if value.is_zero() { return (NegativeImbalance::zero(), Zero::zero()) } - // TODO: rewrite using composite balance. + let old_balance = Self::balance(who); + let mut balance = old_balance.clone(); - let b = Self::reserved_balance(who); - let slash = cmp::min(b, value); // underflow should never happen, but it if does, there's nothing to be done here. - Self::set_reserved_balance(who, b - slash); - (NegativeImbalance::new(slash), value - slash) + let actual = cmp::min(balance.reserved, value); + balance.reserved -= actual; + + Self::set_balances(who, balance, old_balance); + + (NegativeImbalance::new(actual), value - actual) } - // Move the reserved balance of one account into the free balance of another. - // Is a no-op if the value to be moved is zero. + /// Move the reserved balance of one account into the free balance of another. + /// + /// Is a no-op if the value to be moved is zero. fn repatriate_reserved( slashed: &T::AccountId, beneficiary: &T::AccountId, @@ -1285,16 +1239,21 @@ where ) -> result::Result { if value.is_zero() { return Ok (Zero::zero()) } - // TODO: rewrite using composite balance. + let old_to_balance = Self::balance(beneficiary); + let mut to_balance = old_to_balance.clone(); + ensure!(!to_balance.total().is_zero(), Error::::DeadAccount); - if Self::total_balance(beneficiary).is_zero() { - Err(Error::::DeadAccount)? - } - let b = Self::reserved_balance(slashed); - let slash = cmp::min(b, value); - Self::set_free_balance(beneficiary, Self::free_balance(beneficiary) + slash); - Self::set_reserved_balance(slashed, b - slash); - Ok(value - slash) + let old_from_balance = Self::balance(slashed); + let mut from_balance = old_from_balance.clone(); + let actual = cmp::min(from_balance.reserved, value); + + to_balance.free = to_balance.free.checked_add(&actual).ok_or(Error::::Overflow)?; + from_balance.reserved -= actual; + + Self::set_balances(slashed, from_balance, old_from_balance); + Self::set_balances(beneficiary, to_balance, old_to_balance); + + Ok(value - actual) } } @@ -1369,6 +1328,7 @@ where T::Balance: MaybeSerializeDeserialize + Debug { fn is_dead_account(who: &T::AccountId) -> bool { + // this should always be exactly equivalent to `Self::balance(who).total().is_zero()` !Balance::::exists(who) } } diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index 5bf159197b614..2d7340172af8b 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -384,7 +384,8 @@ fn deducting_balance_should_work() { fn refunding_balance_should_work() { ExtBuilder::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 42); - Balances::set_reserved_balance(&1, 69); + let account = Balances::balance(&1); + Balances::set_balances(&1, Account { reserved: 69, ..account }, account); Balances::unreserve(&1, 69); assert_eq!(Balances::free_balance(&1), 111); assert_eq!(Balances::reserved_balance(&1), 0); diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 1695f014a1eaf..21ad668e5a38c 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -88,6 +88,8 @@ pub enum UpdateBalanceOutcome { FreeBalanceZero, /// Reserved balance became zero as a result of this update. ReservedBalanceZero, + /// The account started and ended non-existent. + StillDead, } /// A trait for finding the author of a block header based on the `PreRuntime` digests contained From 63cc7e7c816c14fb2d913bd5f5ee1936bd6b7874 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 23 Jan 2020 15:42:27 +0100 Subject: [PATCH 12/29] Switch out ED to be free + reserved. --- frame/balances/src/lib.rs | 256 ++++++++++++++++-------------------- frame/balances/src/tests.rs | 90 +++++++------ 2 files changed, 167 insertions(+), 179 deletions(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 0d99395b055d2..ba21a6627fbde 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -338,7 +338,7 @@ pub struct BalanceLock { /// All balance information for an account. #[derive(Encode, Decode, Clone, PartialEq, Eq, Default, RuntimeDebug)] -pub struct Account { +pub struct AccountData { /// Non-reserved part of the balance. There may still be restrictions on this, but it is the /// total pool what may in principle be transferred, reserved and used for tipping. /// @@ -370,7 +370,7 @@ pub struct Account { pub fee_frozen: Balance, } -impl Account { +impl AccountData { /// How much this account's balance can be reduced for the given `reasons`. pub fn usable(&self, reasons: Reasons) -> Balance { self.free.saturating_sub(self.frozen(reasons)) @@ -401,11 +401,11 @@ decl_storage! { /// /// NOTE: THIS MAY NEVER BE IN EXISTENCE AND YET HAVE A `total().is_zero()`. If the total /// is ever zero, then the entry *MUST* be removed. - pub Balance get(fn balance) + pub Account get(fn account) build(|config: &GenesisConfig| config.balances.iter() - .map(|&(ref who, free)| (who.clone(), Account { free, .. Default::default() })) + .map(|&(ref who, free)| (who.clone(), AccountData { free, .. Default::default() })) .collect::>() - ): map T::AccountId => Account; + ): map T::AccountId => AccountData; // TODO: Will need to migrate from old FreeBalance, ReservedBalance and the Locks. // TODO: Will need to migrate from Locks. @@ -505,25 +505,26 @@ decl_module! { let who = T::Lookup::lookup(who)?; let existential_deposit = T::ExistentialDeposit::get(); - let new_free = if new_free < existential_deposit { Zero::zero() } else { new_free }; - let new_reserved = if new_reserved < existential_deposit { Zero::zero() } else { new_reserved }; + let wipeout = new_free + new_reserved < existential_deposit; + let new_free = if wipeout { Zero::zero() } else { new_free }; + let new_reserved = if wipeout { Zero::zero() } else { new_reserved }; - let account = Balance::::get(&who); + let old_account = Account::::get(&who); - if new_free > account.free { - mem::drop(PositiveImbalance::::new(new_free - account.free)); - } else if new_free < account.free { - mem::drop(NegativeImbalance::::new(account.free - new_free)); + if new_free > old_account.free { + mem::drop(PositiveImbalance::::new(new_free - old_account.free)); + } else if new_free < old_account.free { + mem::drop(NegativeImbalance::::new(old_account.free - new_free)); } - if new_reserved > account.reserved { - mem::drop(PositiveImbalance::::new(new_reserved - account.reserved)); - } else if new_reserved < account.reserved { - mem::drop(NegativeImbalance::::new(account.reserved - new_reserved)); + if new_reserved > old_account.reserved { + mem::drop(PositiveImbalance::::new(new_reserved - old_account.reserved)); + } else if new_reserved < old_account.reserved { + mem::drop(NegativeImbalance::::new(old_account.reserved - new_reserved)); } - let account = Account { free: new_free, reserved: new_reserved, .. account }; - Balance::::insert(&who, &account); + let account = AccountData { free: new_free, reserved: new_reserved, ..old_account }; + Self::set_account(&who, &account, &old_account); Self::deposit_event(RawEvent::BalanceSet(who, account.free, account.reserved)); } @@ -571,7 +572,7 @@ impl, I: Instance> Module { /// /// Will return `AccountKilled` if either reserved or free are too low. /// - /// NOTE: This assumes that `account` is the same as `Self::balance(who)` except for altered + /// NOTE: This assumes that `account` is the same as `Self::account(who)` except for altered /// values of `free` and `balance`. /// /// NOTE: Doesn't do any preparatory work for creating a new account, so should only be used @@ -579,45 +580,18 @@ impl, I: Instance> Module { /// /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that /// the caller will do this. - fn set_balances( + fn set_account( who: &T::AccountId, - mut account: Account, - old: Account, + account: &AccountData, + old: &AccountData, ) -> UpdateBalanceOutcome { - println!("Setting balance of {:?} to {:?} from {:?}", who, account, Self::balance(who)); - // Commented out for now - but consider it instructive. - // assert!(!Self::total_balance(who).is_zero()); - // assert!(Self::free_balance(who) > T::ExistentialDeposit::get()); - let mut outcome = UpdateBalanceOutcome::Updated; - - let ed = T::ExistentialDeposit::get(); - if account.free < ed { - account.reserved += account.free; - account.free = Zero::zero(); - if old.free >= ed { - T::OnFreeBalanceZero::on_free_balance_zero(who); - outcome = UpdateBalanceOutcome::FreeBalanceZero; - } - } - let mut dust = Zero::zero(); - if account.reserved < ed { - if account.free >= ed { - account.free += account.reserved; - } else { - dust = account.reserved; - } - account.reserved = Zero::zero(); - if old.reserved >= ed { - outcome = UpdateBalanceOutcome::ReservedBalanceZero; - } - } - if !dust.is_zero() { - T::DustRemoval::on_unbalanced(NegativeImbalance::new(dust)); - } - - if account.total().is_zero() { + println!("Setting balance of {:?} to {:?} from {:?}", who, account, Self::account(who)); + let total = account.free + account.reserved; + if total < T::ExistentialDeposit::get() { + T::DustRemoval::on_unbalanced(NegativeImbalance::new(total)); if !old.total().is_zero() { - Self::reap_account(who, dust); + T::OnFreeBalanceZero::on_free_balance_zero(who); + Self::reap_account(who, total); UpdateBalanceOutcome::AccountKilled } else { UpdateBalanceOutcome::StillDead @@ -626,8 +600,8 @@ impl, I: Instance> Module { if old.total().is_zero() { Self::about_to_create_account(who, account.free); } - Balance::::insert(who, account); - outcome + Account::::insert(who, account); + UpdateBalanceOutcome::Updated } } @@ -644,14 +618,14 @@ impl, I: Instance> Module { /// This just removes the nonce and leaves an event. fn reap_account(who: &T::AccountId, dust: T::Balance) { Locks::::remove(who); - Balance::::remove(who); + Account::::remove(who); T::OnReapAccount::on_reap_account(who); Self::deposit_event(RawEvent::ReapedAccount(who.clone(), dust)); } /// Update the account entry for `who`, given the locks. fn update_locks(who: &T::AccountId, locks: &[BalanceLock]) { - Balance::::mutate(who, |b| { + Account::::mutate(who, |b| { b.misc_frozen = Zero::zero(); b.fee_frozen = Zero::zero(); for l in locks.iter() { @@ -879,7 +853,7 @@ impl, I: Instance> Currency for Module where type NegativeImbalance = NegativeImbalance; fn total_balance(who: &T::AccountId) -> Self::Balance { - Self::balance(who).total() + Self::account(who).total() } // Check if `value` amount of free balance can be slashed from `who`. @@ -897,7 +871,7 @@ impl, I: Instance> Currency for Module where } fn free_balance(who: &T::AccountId) -> Self::Balance { - Balance::::get(who).free + Account::::get(who).free } // Burn funds from the total issuance, returning a positive imbalance for the amount burned. @@ -942,7 +916,7 @@ impl, I: Instance> Currency for Module where new_balance: T::Balance, ) -> DispatchResult { if amount.is_zero() { return Ok(()) } - let min_balance = Balance::::get(who).frozen(reasons.into()); + let min_balance = Account::::get(who).frozen(reasons.into()); ensure!(new_balance >= min_balance, Error::::LiquidityRestrictions); Ok(()) } @@ -957,43 +931,43 @@ impl, I: Instance> Currency for Module where ) -> DispatchResult { if value.is_zero() || transactor == dest { return Ok(()) } - let old_from_balance = Self::balance(transactor); - let mut from_balance = old_from_balance.clone(); - let old_to_balance = Self::balance(dest); - let mut to_balance = old_to_balance.clone(); + let old_from_account = Self::account(transactor); + let mut from_account = old_from_account.clone(); + let old_to_account = Self::account(dest); + let mut to_account = old_to_account.clone(); - let would_create = to_balance.total().is_zero(); + let would_create = to_account.total().is_zero(); let fee = if would_create { T::CreationFee::get() } else { Zero::zero() }; let liability = value.checked_add(&fee).ok_or(Error::::Overflow)?; - from_balance.free = from_balance.free.checked_sub(&liability) + from_account.free = from_account.free.checked_sub(&liability) .ok_or(Error::::InsufficientBalance)?; // NOTE: total stake being stored in the same type means that this could never overflow // but better to be safe than sorry. - to_balance.free = to_balance.free.checked_add(&value).ok_or(Error::::Overflow)?; + to_account.free = to_account.free.checked_add(&value).ok_or(Error::::Overflow)?; let ed = T::ExistentialDeposit::get(); - ensure!(to_balance.free >= ed, Error::::ExistentialDeposit); + ensure!(to_account.free >= ed, Error::::ExistentialDeposit); Self::ensure_can_withdraw( transactor, value, WithdrawReason::Transfer.into(), - from_balance.free, + from_account.free, )?; let allow_death = existence_requirement == ExistenceRequirement::AllowDeath; - ensure!(allow_death || from_balance.free >= ed, Error::::KeepAlive); + ensure!(allow_death || from_account.free >= ed, Error::::KeepAlive); - Self::set_balances(transactor, from_balance, old_from_balance); + Self::set_account(transactor, &from_account, &old_from_account); // Emit transfer event. Self::deposit_event(RawEvent::Transfer(transactor.clone(), dest.clone(), value, fee)); - // Take action on the set_balances call. + // Take action on the set_account call. // This will emit events that _resulted_ from the transfer. - Self::set_balances(dest, to_balance, old_to_balance); + Self::set_account(dest, &to_account, &old_to_account); T::TransferPayment::on_unbalanced(NegativeImbalance::new(fee)); @@ -1010,21 +984,21 @@ impl, I: Instance> Currency for Module where ) -> result::Result { if value.is_zero() { return Ok(NegativeImbalance::zero()); } - let old_balance = Self::balance(who); - let mut balance = old_balance.clone(); - if let Some(new_free_balance) = balance.free.checked_sub(&value) { + let old_account = Self::account(who); + let mut account = old_account.clone(); + if let Some(new_free_account) = account.free.checked_sub(&value) { // if we need to keep the account alive... if liveness == ExistenceRequirement::KeepAlive // ...and it would be dead afterwards... - && new_free_balance < T::ExistentialDeposit::get() + && new_free_account < T::ExistentialDeposit::get() // ...yet is was alive before - && balance.free >= T::ExistentialDeposit::get() + && account.free >= T::ExistentialDeposit::get() { Err(Error::::KeepAlive)? } - Self::ensure_can_withdraw(who, value, reasons, new_free_balance)?; - balance.free = new_free_balance; - Self::set_balances(who, balance, old_balance); + Self::ensure_can_withdraw(who, value, reasons, new_free_account)?; + account.free = new_free_account; + Self::set_account(who, &account, &old_account); Ok(NegativeImbalance::new(value)) } else { Err(Error::::InsufficientBalance)? @@ -1046,21 +1020,21 @@ impl, I: Instance> Currency for Module where ) -> (Self::NegativeImbalance, Self::Balance) { if value.is_zero() { return (NegativeImbalance::zero(), Zero::zero()) } - let old_balance = Self::balance(who); - let mut balance = old_balance.clone(); + let old_account = Self::account(who); + let mut account = old_account.clone(); - let free_slash = cmp::min(balance.free, value); - balance.free -= free_slash; + let free_slash = cmp::min(account.free, value); + account.free -= free_slash; let remaining_slash = value - free_slash; let result = if !remaining_slash.is_zero() { - let reserved_slash = cmp::min(balance.reserved, remaining_slash); - balance.reserved -= reserved_slash; + let reserved_slash = cmp::min(account.reserved, remaining_slash); + account.reserved -= reserved_slash; (NegativeImbalance::new(free_slash + reserved_slash), remaining_slash - reserved_slash) } else { (NegativeImbalance::new(value), Zero::zero()) }; - Self::set_balances(who, balance, old_balance); + Self::set_account(who, &account, &old_account); result } @@ -1073,12 +1047,12 @@ impl, I: Instance> Currency for Module where ) -> result::Result { if value.is_zero() { return Ok(PositiveImbalance::zero()) } - let old_balance = Self::balance(who); - let mut balance = old_balance.clone(); - ensure!(!balance.total().is_zero(), Error::::DeadAccount); - balance.free = balance.free.checked_add(&value).ok_or(Error::::Overflow)?; + let old_account = Self::account(who); + let mut account = old_account.clone(); + ensure!(!account.total().is_zero(), Error::::DeadAccount); + account.free = account.free.checked_add(&value).ok_or(Error::::Overflow)?; - Self::set_balances(who, balance, old_balance); + Self::set_account(who, &account, &old_account); Ok(PositiveImbalance::new(value)) } @@ -1094,21 +1068,21 @@ impl, I: Instance> Currency for Module where ) -> Self::PositiveImbalance { if value.is_zero() { return Self::PositiveImbalance::zero() } - let old_balance = Self::balance(who); - let mut balance = old_balance.clone(); + let old_account = Self::account(who); + let mut account = old_account.clone(); let ed = T::ExistentialDeposit::get(); // bail if not yet created and this operation wouldn't be enough to create it. - if value < ed && balance.total().is_zero() { return Self::PositiveImbalance::zero() } + if value < ed && account.total().is_zero() { return Self::PositiveImbalance::zero() } // defensive only: overflow should never happen, however in case it does, then this // operation is a no-op. - balance.free = match balance.free.checked_add(&value) { + account.free = match account.free.checked_add(&value) { Some(f) => f, None => return Self::PositiveImbalance::zero(), }; - Self::set_balances(who, balance, old_balance); + Self::set_account(who, &account, &old_account); PositiveImbalance::new(value) } @@ -1118,14 +1092,14 @@ impl, I: Instance> Currency for Module where SignedImbalance, UpdateBalanceOutcome ) { - let old_balance = Self::balance(who); - let mut balance = old_balance.clone(); + let old_account = Self::account(who); + let mut account = old_account.clone(); - if value < T::ExistentialDeposit::get() && balance.free.is_zero() { + if value < T::ExistentialDeposit::get() && account.free.is_zero() { // If we're attempting to set an existing account to less than ED, then // bypass the entire operation. It's a no-op if you follow it through, but // since this is an instance where we might account for a negative imbalance - // (in the dust cleaner of set_balances) before we account for its actual + // (in the dust cleaner of set_account) before we account for its actual // equal and opposite cause (returned as an Imbalance), then in the // instance that there's no other accounts on the system at all, we might // underflow the issuance and our arithmetic will be off. @@ -1134,18 +1108,18 @@ impl, I: Instance> Currency for Module where UpdateBalanceOutcome::AccountKilled, ) } - let imbalance = if balance.free <= value { - SignedImbalance::Positive(PositiveImbalance::new(value - balance.free)) + let imbalance = if account.free <= value { + SignedImbalance::Positive(PositiveImbalance::new(value - account.free)) } else { - SignedImbalance::Negative(NegativeImbalance::new(balance.free - value)) + SignedImbalance::Negative(NegativeImbalance::new(account.free - value)) }; - balance.free = value; + account.free = value; // If the balance is too low, then the account is reaped. // Free balance can never be less than ED. If that happens, it gets reduced to zero // and the account information relevant to this subsystem is deleted (i.e. the // account is reaped). - let outcome = Self::set_balances(who, balance, old_balance); + let outcome = Self::set_account(who, &account, &old_account); (imbalance, outcome) } } @@ -1159,7 +1133,7 @@ where /// Always `true` if value to be reserved is zero. fn can_reserve(who: &T::AccountId, value: Self::Balance) -> bool { if value.is_zero() { return true } - Self::free_balance(who) + Self::account(who).free .checked_sub(&value) .map_or(false, |new_balance| Self::ensure_can_withdraw(who, value, WithdrawReason::Reserve.into(), new_balance).is_ok() @@ -1167,7 +1141,7 @@ where } fn reserved_balance(who: &T::AccountId) -> Self::Balance { - Self::balance(who).reserved + Self::account(who).reserved } /// Move `value` from the free balance from `who` to their reserved balance. @@ -1176,14 +1150,14 @@ where fn reserve(who: &T::AccountId, value: Self::Balance) -> result::Result<(), DispatchError> { if value.is_zero() { return Ok(()) } - let old_balance = Self::balance(who); - let mut balance = old_balance.clone(); + let old_account = Self::account(who); + let mut account = old_account.clone(); - balance.free = balance.free.checked_sub(&value).ok_or(Error::::InsufficientBalance)?; - balance.reserved = balance.reserved.checked_add(&value).ok_or(Error::::Overflow)?; - Self::ensure_can_withdraw(who, value, WithdrawReason::Reserve.into(), balance.free)?; + account.free = account.free.checked_sub(&value).ok_or(Error::::InsufficientBalance)?; + account.reserved = account.reserved.checked_add(&value).ok_or(Error::::Overflow)?; + Self::ensure_can_withdraw(who, value, WithdrawReason::Reserve.into(), account.free)?; - Self::set_balances(who, balance, old_balance); + Self::set_account(who, &account, &old_account); Ok(()) } @@ -1193,16 +1167,16 @@ where fn unreserve(who: &T::AccountId, value: Self::Balance) -> Self::Balance { if value.is_zero() { return Zero::zero() } - let old_balance = Self::balance(who); - let mut balance = old_balance.clone(); + let old_account = Self::account(who); + let mut account = old_account.clone(); - let actual = cmp::min(balance.reserved, value); - balance.reserved -= actual; - // defensive only: this can never fail since total issuance which is at least free+reservred + let actual = cmp::min(account.reserved, value); + account.reserved -= actual; + // defensive only: this can never fail since total issuance which is at least free+reserved // fits into the same datatype. - balance.free = balance.free.saturating_add(actual); + account.free = account.free.saturating_add(actual); - Self::set_balances(who, balance, old_balance); + Self::set_account(who, &account, &old_account); value - actual } @@ -1217,14 +1191,14 @@ where ) -> (Self::NegativeImbalance, Self::Balance) { if value.is_zero() { return (NegativeImbalance::zero(), Zero::zero()) } - let old_balance = Self::balance(who); - let mut balance = old_balance.clone(); + let old_account = Self::account(who); + let mut account = old_account.clone(); // underflow should never happen, but it if does, there's nothing to be done here. - let actual = cmp::min(balance.reserved, value); - balance.reserved -= actual; + let actual = cmp::min(account.reserved, value); + account.reserved -= actual; - Self::set_balances(who, balance, old_balance); + Self::set_account(who, &account, &old_account); (NegativeImbalance::new(actual), value - actual) } @@ -1239,19 +1213,19 @@ where ) -> result::Result { if value.is_zero() { return Ok (Zero::zero()) } - let old_to_balance = Self::balance(beneficiary); - let mut to_balance = old_to_balance.clone(); - ensure!(!to_balance.total().is_zero(), Error::::DeadAccount); + let old_to_account = Self::account(beneficiary); + let mut to_account = old_to_account.clone(); + ensure!(!to_account.total().is_zero(), Error::::DeadAccount); - let old_from_balance = Self::balance(slashed); - let mut from_balance = old_from_balance.clone(); - let actual = cmp::min(from_balance.reserved, value); + let old_from_account = Self::account(slashed); + let mut from_account = old_from_account.clone(); + let actual = cmp::min(from_account.reserved, value); - to_balance.free = to_balance.free.checked_add(&actual).ok_or(Error::::Overflow)?; - from_balance.reserved -= actual; + to_account.free = to_account.free.checked_add(&actual).ok_or(Error::::Overflow)?; + from_account.reserved -= actual; - Self::set_balances(slashed, from_balance, old_from_balance); - Self::set_balances(beneficiary, to_balance, old_to_balance); + Self::set_account(slashed, &from_account, &old_from_account); + Self::set_account(beneficiary, &to_account, &old_to_account); Ok(value - actual) } @@ -1328,7 +1302,7 @@ where T::Balance: MaybeSerializeDeserialize + Debug { fn is_dead_account(who: &T::AccountId) -> bool { - // this should always be exactly equivalent to `Self::balance(who).total().is_zero()` - !Balance::::exists(who) + // this should always be exactly equivalent to `Self::account(who).total().is_zero()` + !Account::::exists(who) } } diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index 2d7340172af8b..00b6af5a3f736 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -234,7 +234,7 @@ fn reserved_balance_should_prevent_reclaim_count() { assert_eq!(Balances::total_balance(&2), 256 * 20); assert_ok!(Balances::reserve(&2, 256 * 19 + 1)); // account 2 becomes mostly reserved - assert_eq!(Balances::free_balance(&2), 0); // "free" account deleted." + assert_eq!(Balances::free_balance(&2), 255); // "free" account deleted." assert_eq!(Balances::total_balance(&2), 256 * 20); // reserve still exists. assert_eq!(Balances::is_dead_account(&2), false); assert_eq!(System::account_nonce(&2), 1); @@ -384,8 +384,8 @@ fn deducting_balance_should_work() { fn refunding_balance_should_work() { ExtBuilder::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 42); - let account = Balances::balance(&1); - Balances::set_balances(&1, Account { reserved: 69, ..account }, account); + let account = Balances::account(&1); + Balances::set_account(&1, &AccountData { reserved: 69, ..account }, &account); Balances::unreserve(&1, 69); assert_eq!(Balances::free_balance(&1), 111); assert_eq!(Balances::reserved_balance(&1), 0); @@ -491,8 +491,8 @@ fn transferring_incomplete_reserved_balance_should_work() { #[test] fn transferring_too_high_value_should_not_panic() { ExtBuilder::default().build().execute_with(|| { - >::insert(1, Account { free: u64::max_value(), .. Default::default() }); - >::insert(2, Account { free: 1, .. Default::default() }); + Account::::insert(1, AccountData { free: u64::max_value(), .. Default::default() }); + Account::::insert(2, AccountData { free: 1, .. Default::default() }); assert_err!( Balances::transfer(Some(1).into(), 2, u64::max_value()), @@ -606,38 +606,52 @@ fn cannot_set_genesis_value_below_ed() { #[test] fn dust_moves_between_free_and_reserved() { ExtBuilder::default() - .existential_deposit(100) - .build() - .execute_with(|| { - // Set balance to free and reserved at the existential deposit - assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 100, 100)); - assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 2, 100, 100)); - // Check balance - assert_eq!(Balances::free_balance(&1), 100); - assert_eq!(Balances::reserved_balance(&1), 100); - assert_eq!(Balances::free_balance(&2), 100); - assert_eq!(Balances::reserved_balance(&2), 100); - - // Drop 1 free_balance below ED - assert_ok!(Balances::transfer(Some(1).into(), 2, 1)); - // Check balance, the other 99 should move to reserved_balance - assert_eq!(Balances::free_balance(&1), 0); - assert_eq!(Balances::reserved_balance(&1), 199); - - // Reset accounts - assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 100, 100)); - assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 2, 100, 100)); - - // Drop 2 reserved_balance below ED - Balances::unreserve(&2, 1); - // Check balance, all 100 should move to free_balance - assert_eq!(Balances::free_balance(&2), 200); - assert_eq!(Balances::reserved_balance(&2), 0); + .existential_deposit(100) + .build() + .execute_with(|| { + // Set balance to free and reserved at the existential deposit + assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 100, 0)); + // Check balance + assert_eq!(Balances::free_balance(&1), 100); + assert_eq!(Balances::reserved_balance(&1), 0); + + // Reserve some free balance + assert_ok!(Balances::reserve(&1, 50)); + // Check balance, the account should be ok. + assert_eq!(Balances::free_balance(&1), 50); + assert_eq!(Balances::reserved_balance(&1), 50); + + // Reserve the rest of the free balance + assert_ok!(Balances::reserve(&1, 50)); + // Check balance, the account should be ok. + assert_eq!(Balances::free_balance(&1), 0); + assert_eq!(Balances::reserved_balance(&1), 100); + + // Unreserve everything + Balances::unreserve(&1, 100); + // Check balance, all 100 should move to free_balance + assert_eq!(Balances::free_balance(&1), 100); + assert_eq!(Balances::reserved_balance(&1), 0); + }); +} - // An account with both too little free and reserved is completely killed - assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 99, 99)); - // Check balance is 0 for everything - assert_eq!(Balances::free_balance(&1), 0); - assert_eq!(Balances::reserved_balance(&1), 0); - }); +#[test] +fn account_deleted_when_just_dust() { + ExtBuilder::default() + .existential_deposit(100) + .build() + .execute_with(|| { + // Set balance to free and reserved at the existential deposit + assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 50, 50)); + // Check balance + assert_eq!(Balances::free_balance(&1), 50); + assert_eq!(Balances::reserved_balance(&1), 50); + + // Reserve some free balance + let _ = Balances::slash(&1, 1); + // The account should be dead. + assert!(Balances::is_dead_account(&1)); + assert_eq!(Balances::free_balance(&1), 0); + assert_eq!(Balances::reserved_balance(&1), 0); + }); } From cca0c113a31294dcb58c11e2fb45d31fce10622c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 23 Jan 2020 15:53:16 +0100 Subject: [PATCH 13/29] Remove on_free_balance_zero and some docs. --- bin/node-template/runtime/src/lib.rs | 2 - bin/node/runtime/src/lib.rs | 3 +- frame/balances/src/lib.rs | 62 +++++++--------------------- frame/balances/src/mock.rs | 1 - frame/contracts/src/account_db.rs | 2 +- frame/contracts/src/lib.rs | 6 +-- frame/contracts/src/tests.rs | 3 +- frame/democracy/src/lib.rs | 9 ++-- frame/elections-phragmen/src/lib.rs | 3 +- frame/elections/src/mock.rs | 1 - frame/example/src/lib.rs | 3 +- frame/executive/src/lib.rs | 3 +- frame/identity/src/lib.rs | 3 +- frame/nicks/src/lib.rs | 1 - frame/recovery/src/mock.rs | 1 - frame/scored-pool/src/mock.rs | 1 - frame/session/src/lib.rs | 8 ++-- frame/society/src/mock.rs | 1 - frame/staking/src/lib.rs | 7 ++-- frame/staking/src/mock.rs | 3 +- frame/support/src/traits.rs | 11 +---- frame/transaction-payment/src/lib.rs | 3 +- frame/treasury/src/lib.rs | 3 +- frame/utility/src/lib.rs | 3 +- frame/vesting/src/lib.rs | 3 +- 25 files changed, 44 insertions(+), 102 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index cee3111adc0e5..49bf9628ef5e7 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -202,8 +202,6 @@ parameter_types! { impl balances::Trait for Runtime { /// The type for recording an account's balance. type Balance = Balance; - /// What to do if an account's free balance gets zeroed. - type OnFreeBalanceZero = (); /// What to do if an account is fully reaped from the system. type OnReapAccount = System; /// What to do if a new account is created. diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 3c863d6fccb07..5c3f1099695bb 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -172,8 +172,7 @@ parameter_types! { impl pallet_balances::Trait for Runtime { type Balance = Balance; - type OnFreeBalanceZero = ((Staking, Contracts), Session); - type OnReapAccount = (System, Recovery); + type OnReapAccount = ((((System, Staking), Contracts), Session), Recovery); type OnNewAccount = Indices; type Event = Event; type DustRemoval = (); diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index ba21a6627fbde..d7ccad81f4b39 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -38,33 +38,29 @@ //! ### Terminology //! //! - **Existential Deposit:** The minimum balance required to create or keep an account open. This prevents -//! "dust accounts" from filling storage. -//! - **Total Issuance:** The total number of units in existence in a system. -//! - **Reaping an account:** The act of removing an account by resetting its nonce. Happens after its balance is set -//! to zero. -//! - **Free Balance:** The portion of a balance that is not reserved. The free balance is the only -//! balance that matters for most operations. When this balance falls below the existential -//! deposit, most functionality of the account is removed. When both it and the reserved balance -//! are deleted, then the account is said to be dead. -//! -//! No account should ever have a free balance that is strictly between 0 and the existential +//! "dust accounts" from filling storage. When the free plus the reserved balance (i.e. the total balance) +//! fall below this, then the account is said to be dead; and it loses its functionality as well as any +//! prior history and all information on it is removed from the chain's state. +//! No account should ever have a total balance that is strictly between 0 and the existential //! deposit (exclusive). If this ever happens, it indicates either a bug in this module or an //! erroneous raw mutation of storage. //! +//! - **Total Issuance:** The total number of units in existence in a system. +//! +//! - **Reaping an account:** The act of removing an account by resetting its nonce. Happens after its +//! total balance has become zero (or, strictly speaking, less than the Existential Deposit). +//! +//! - **Free Balance:** The portion of a balance that is not reserved. The free balance is the only +//! balance that matters for most operations. +//! //! - **Reserved Balance:** Reserved balance still belongs to the account holder, but is suspended. //! Reserved balance can still be slashed, but only after all the free balance has been slashed. -//! If the reserved balance falls below the existential deposit, it and any related functionality -//! will be deleted. When both it and the free balance are deleted, then the account is said to -//! be dead. -//! -//! No account should ever have a reserved balance that is strictly between 0 and the existential -//! deposit (exclusive). If this ever happens, it indicates either a bug in this module or an -//! erroneous raw mutation of storage. //! //! - **Imbalance:** A condition when some funds were credited or debited without equal and opposite accounting //! (i.e. a difference between total issuance and account balances). Functions that result in an imbalance will //! return an object of the `Imbalance` trait that can be managed within your runtime logic. (If an imbalance is //! simply dropped, it should automatically maintain any book-keeping such as total issuance.) +//! //! - **Lock:** A freeze on a specified amount of an account's free balance until a specified block number. Multiple //! locks always operate over the same funds, so they "overlay" rather than "stack". //! @@ -158,7 +154,7 @@ use codec::{Codec, Encode, Decode}; use frame_support::{ StorageValue, Parameter, decl_event, decl_storage, decl_module, decl_error, ensure, traits::{ - UpdateBalanceOutcome, Currency, OnFreeBalanceZero, OnReapAccount, OnUnbalanced, TryDrop, + UpdateBalanceOutcome, Currency, OnReapAccount, OnUnbalanced, TryDrop, WithdrawReason, WithdrawReasons, LockIdentifier, LockableCurrency, ExistenceRequirement, Imbalance, SignedImbalance, ReservableCurrency, Get, }, @@ -185,12 +181,6 @@ pub trait Subtrait: frame_system::Trait { type Balance: Parameter + Member + SimpleArithmetic + Codec + Default + Copy + MaybeSerializeDeserialize + Debug; - /// A function that is invoked when the free-balance has fallen below the existential deposit and - /// has been reduced to zero. - /// - /// Gives a chance to clean up resources associated with the given account. - type OnFreeBalanceZero: OnFreeBalanceZero; - /// A function that is invoked when the free-balance and the reserved-balance has fallen below /// the existential deposit and both have been reduced to zero. /// @@ -213,12 +203,6 @@ pub trait Trait: frame_system::Trait { type Balance: Parameter + Member + SimpleArithmetic + Codec + Default + Copy + MaybeSerializeDeserialize + Debug; - /// A function that is invoked when the free-balance has fallen below the existential deposit and - /// has been reduced to zero. - /// - /// Gives a chance to clean up resources associated with the given account. - type OnFreeBalanceZero: OnFreeBalanceZero; - /// A function that is invoked when the free-balance and the reserved-balance has fallen below /// the existential deposit and both have been reduced to zero. /// @@ -247,7 +231,6 @@ pub trait Trait: frame_system::Trait { impl, I: Instance> Subtrait for T { type Balance = T::Balance; - type OnFreeBalanceZero = T::OnFreeBalanceZero; type OnReapAccount = T::OnReapAccount; type OnNewAccount = T::OnNewAccount; type ExistentialDeposit = T::ExistentialDeposit; @@ -343,14 +326,7 @@ pub struct AccountData { /// total pool what may in principle be transferred, reserved and used for tipping. /// /// This is the only balance that matters in terms of most operations on tokens. It - /// alone is used to determine the balance when in the contract execution environment. When this - /// balance falls below the value of `ExistentialDeposit`, then the 'current account' is - /// deleted: specifically `free`. Further, the `OnFreeBalanceZero` callback - /// is invoked, giving a chance to external modules to clean up data associated with - /// the deleted account. - /// - /// `frame_system::AccountNonce` is also deleted if `reserved` is also zero (it also gets - /// collapsed to zero if it ever becomes less than `ExistentialDeposit`. + /// alone is used to determine the balance when in the contract execution environment. pub free: Balance, /// Balance which is reserved and may not be used at all. /// @@ -358,9 +334,6 @@ pub struct AccountData { /// /// This balance is a 'reserve' balance that other subsystems use in order to set aside tokens /// that are still 'owned' by the account holder, but which are suspendable. - /// - /// When this balance falls below the value of `ExistentialDeposit`, then any remainder is - /// coalesced into `free`. pub reserved: Balance, /// The amount that `free` may not drop below when withdrawing for *anything except transaction /// fee payment*. @@ -464,8 +437,7 @@ decl_module! { /// - `ensure_can_withdraw` is always called internally but has a bounded complexity. /// - Transferring balances to accounts that did not exist before will cause /// `T::OnNewAccount::on_new_account` to be called. - /// - Removing enough funds from an account will trigger - /// `T::DustRemoval::on_unbalanced` and `T::OnFreeBalanceZero::on_free_balance_zero`. + /// - Removing enough funds from an account will trigger `T::DustRemoval::on_unbalanced`. /// - `transfer_keep_alive` works the same way as `transfer`, but has an additional /// check that the transfer will not kill the origin account. /// @@ -590,7 +562,6 @@ impl, I: Instance> Module { if total < T::ExistentialDeposit::get() { T::DustRemoval::on_unbalanced(NegativeImbalance::new(total)); if !old.total().is_zero() { - T::OnFreeBalanceZero::on_free_balance_zero(who); Self::reap_account(who, total); UpdateBalanceOutcome::AccountKilled } else { @@ -835,7 +806,6 @@ impl, I: Instance> frame_system::Trait for ElevatedTrait { } impl, I: Instance> Trait for ElevatedTrait { type Balance = T::Balance; - type OnFreeBalanceZero = T::OnFreeBalanceZero; type OnReapAccount = T::OnReapAccount; type OnNewAccount = T::OnNewAccount; type Event = (); diff --git a/frame/balances/src/mock.rs b/frame/balances/src/mock.rs index f4b932e192a05..5eb722733f464 100644 --- a/frame/balances/src/mock.rs +++ b/frame/balances/src/mock.rs @@ -86,7 +86,6 @@ impl pallet_transaction_payment::Trait for Test { } impl Trait for Test { type Balance = u64; - type OnFreeBalanceZero = (); type OnReapAccount = System; type OnNewAccount = (); type Event = (); diff --git a/frame/contracts/src/account_db.rs b/frame/contracts/src/account_db.rs index 3615673f2d9dc..814983c5860f6 100644 --- a/frame/contracts/src/account_db.rs +++ b/frame/contracts/src/account_db.rs @@ -149,7 +149,7 @@ impl AccountDb for DirectAccountDb { let (imbalance, outcome) = T::Currency::make_free_balance_be(&address, balance); total_imbalance = total_imbalance.merge(imbalance); if let UpdateBalanceOutcome::AccountKilled = outcome { - // Account killed. This will ultimately lead to calling `OnFreeBalanceZero` callback + // Account killed. This will ultimately lead to calling `OnReapAccount` callback // which will make removal of CodeHashOf and AccountStorage for this account. // In order to avoid writing over the deleted properties we `continue` here. continue; diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 7e6a6e6192ccf..2cf2855b82966 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -125,7 +125,7 @@ use frame_support::{ parameter_types, IsSubType, weights::DispatchInfo, }; -use frame_support::traits::{OnFreeBalanceZero, OnUnbalanced, Currency, Get, Time, Randomness}; +use frame_support::traits::{OnReapAccount, OnUnbalanced, Currency, Get, Time, Randomness}; use frame_system::{self as system, ensure_signed, RawOrigin, ensure_root}; use sp_core::storage::well_known_keys::CHILD_STORAGE_KEY_PREFIX; @@ -948,8 +948,8 @@ decl_storage! { } } -impl OnFreeBalanceZero for Module { - fn on_free_balance_zero(who: &T::AccountId) { +impl OnReapAccount for Module { + fn on_reap_account(who: &T::AccountId) { if let Some(ContractInfo::Alive(info)) = >::take(who) { child::kill_storage(&info.trie_id, info.child_trie_unique_id()); } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index b3fa381422bb9..2256921287654 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -121,8 +121,7 @@ impl frame_system::Trait for Test { } impl pallet_balances::Trait for Test { type Balance = u64; - type OnFreeBalanceZero = Contract; - type OnReapAccount = System; + type OnReapAccount = (System, Contract); type OnNewAccount = (); type Event = MetaEvent; type DustRemoval = (); diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index e1477f322538d..20f18b86163a9 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -30,7 +30,7 @@ use frame_support::{ weights::SimpleDispatchInfo, traits::{ Currency, ReservableCurrency, LockableCurrency, WithdrawReason, LockIdentifier, Get, - OnFreeBalanceZero, OnUnbalanced + OnReapAccount, OnUnbalanced } }; use frame_system::{self as system, ensure_signed, ensure_root}; @@ -1155,8 +1155,8 @@ impl Module { } } -impl OnFreeBalanceZero for Module { - fn on_free_balance_zero(who: &T::AccountId) { +impl OnReapAccount for Module { + fn on_reap_account(who: &T::AccountId) { >::remove(who) } } @@ -1226,8 +1226,7 @@ mod tests { } impl pallet_balances::Trait for Test { type Balance = u64; - type OnFreeBalanceZero = (); - type OnReapAccount = System; +type OnReapAccount = System; type OnNewAccount = (); type Event = (); type TransferPayment = (); diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 4da0de23e3f32..bab6b153e23c1 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -821,8 +821,7 @@ mod tests { impl pallet_balances::Trait for Test { type Balance = u64; type OnNewAccount = (); - type OnFreeBalanceZero = (); - type OnReapAccount = System; +type OnReapAccount = System; type Event = Event; type TransferPayment = (); type DustRemoval = (); diff --git a/frame/elections/src/mock.rs b/frame/elections/src/mock.rs index 87a660bc3f180..9a4789a51d277 100644 --- a/frame/elections/src/mock.rs +++ b/frame/elections/src/mock.rs @@ -63,7 +63,6 @@ parameter_types! { impl pallet_balances::Trait for Test { type Balance = u64; type OnNewAccount = (); - type OnFreeBalanceZero = (); type OnReapAccount = System; type Event = Event; type TransferPayment = (); diff --git a/frame/example/src/lib.rs b/frame/example/src/lib.rs index 9cebed7de810b..6463c33f499e4 100644 --- a/frame/example/src/lib.rs +++ b/frame/example/src/lib.rs @@ -693,8 +693,7 @@ mod tests { } impl pallet_balances::Trait for Test { type Balance = u64; - type OnFreeBalanceZero = (); - type OnReapAccount = System; +type OnReapAccount = System; type OnNewAccount = (); type Event = (); type TransferPayment = (); diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 634cb54696284..c7ab708ade903 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -459,8 +459,7 @@ mod tests { } impl pallet_balances::Trait for Runtime { type Balance = u64; - type OnFreeBalanceZero = (); - type OnReapAccount = System; +type OnReapAccount = System; type OnNewAccount = (); type Event = MetaEvent; type DustRemoval = (); diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index ecd5ca92580c3..f6013c93d0ac8 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -918,8 +918,7 @@ mod tests { } impl pallet_balances::Trait for Test { type Balance = u64; - type OnFreeBalanceZero = (); - type OnReapAccount = System; +type OnReapAccount = System; type OnNewAccount = (); type Event = (); type TransferPayment = (); diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index 2d816e4a55bc2..ec696dc6a843c 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -292,7 +292,6 @@ mod tests { } impl pallet_balances::Trait for Test { type Balance = u64; - type OnFreeBalanceZero = (); type OnReapAccount = System; type OnNewAccount = (); type Event = (); diff --git a/frame/recovery/src/mock.rs b/frame/recovery/src/mock.rs index 24ca9ff9d6d50..fa074e1faf56b 100644 --- a/frame/recovery/src/mock.rs +++ b/frame/recovery/src/mock.rs @@ -86,7 +86,6 @@ parameter_types! { impl pallet_balances::Trait for Test { type Balance = u128; - type OnFreeBalanceZero = (); type OnReapAccount = (System, Recovery); type OnNewAccount = (); type Event = TestEvent; diff --git a/frame/scored-pool/src/mock.rs b/frame/scored-pool/src/mock.rs index e55869fc74f00..fa8b11e69ef31 100644 --- a/frame/scored-pool/src/mock.rs +++ b/frame/scored-pool/src/mock.rs @@ -75,7 +75,6 @@ impl frame_system::Trait for Test { impl pallet_balances::Trait for Test { type Balance = u64; - type OnFreeBalanceZero = (); type OnReapAccount = System; type OnNewAccount = (); type Event = (); diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 098b5330779ef..6609733b6f950 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -126,7 +126,7 @@ use frame_support::weights::SimpleDispatchInfo; use sp_runtime::traits::{Convert, Zero, Member, OpaqueKeys}; use sp_staking::SessionIndex; use frame_support::{dispatch, ConsensusEngineId, decl_module, decl_event, decl_storage, decl_error}; -use frame_support::{ensure, traits::{OnFreeBalanceZero, Get, FindAuthor, ValidatorRegistration}, Parameter}; +use frame_support::{ensure, traits::{OnReapAccount, Get, FindAuthor, ValidatorRegistration}, Parameter}; use frame_system::{self as system, ensure_signed}; #[cfg(test)] @@ -696,8 +696,8 @@ impl Module { } } -impl OnFreeBalanceZero for Module { - fn on_free_balance_zero(who: &T::ValidatorId) { +impl OnReapAccount for Module { + fn on_reap_account(who: &T::ValidatorId) { Self::prune_dead_keys(who); } } @@ -774,7 +774,7 @@ mod tests { let id = DUMMY; assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(id)), Some(1)); - Session::on_free_balance_zero(&1); + Session::on_reap_account(&1); assert_eq!(Session::load_keys(&1), None); assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(id)), None); }) diff --git a/frame/society/src/mock.rs b/frame/society/src/mock.rs index 28904ba4b8ec5..5c772478c871c 100644 --- a/frame/society/src/mock.rs +++ b/frame/society/src/mock.rs @@ -80,7 +80,6 @@ impl frame_system::Trait for Test { impl pallet_balances::Trait for Test { type Balance = u64; - type OnFreeBalanceZero = (); type OnNewAccount = (); type Event = (); type TransferPayment = (); diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 4c7be2f46f02a..a408a434326de 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -261,7 +261,7 @@ use frame_support::{ decl_module, decl_event, decl_storage, ensure, decl_error, weights::SimpleDispatchInfo, traits::{ - Currency, OnFreeBalanceZero, LockIdentifier, LockableCurrency, + Currency, LockIdentifier, LockableCurrency, WithdrawReasons, OnUnbalanced, Imbalance, Get, Time } }; @@ -284,6 +284,7 @@ use sp_runtime::{Serialize, Deserialize}; use frame_system::{self as system, ensure_signed, ensure_root}; use sp_phragmen::ExtendedBalance; +use frame_support::traits::OnReapAccount; const DEFAULT_MINIMUM_VALIDATOR_COUNT: u32 = 4; const MAX_NOMINATIONS: usize = 16; @@ -1673,8 +1674,8 @@ impl SessionManager> } } -impl OnFreeBalanceZero for Module { - fn on_free_balance_zero(stash: &T::AccountId) { +impl OnReapAccount for Module { + fn on_reap_account(stash: &T::AccountId) { Self::ensure_storage_upgraded(); Self::kill_stash(stash); } diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 585bab79b2d8e..3b2443c2cec73 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -144,8 +144,7 @@ parameter_types! { } impl pallet_balances::Trait for Test { type Balance = Balance; - type OnFreeBalanceZero = Staking; - type OnReapAccount = System; + type OnReapAccount = (System, Staking); type OnNewAccount = (); type Event = (); type TransferPayment = (); diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 21ad668e5a38c..02e6085046ad0 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -64,13 +64,6 @@ pub trait Contains { fn count() -> usize { Self::sorted_members().len() } } -/// The account with the given id was killed. -#[impl_trait_for_tuples::impl_for_tuples(30)] -pub trait OnFreeBalanceZero { - /// The account with the given id was killed. - fn on_free_balance_zero(who: &AccountId); -} - /// The account with the given id was reaped. #[impl_trait_for_tuples::impl_for_tuples(30)] pub trait OnReapAccount { @@ -382,9 +375,7 @@ pub trait Currency { /// This is the only balance that matters in terms of most operations on tokens. It alone /// is used to determine the balance when in the contract execution environment. When this /// balance falls below the value of `ExistentialDeposit`, then the 'current account' is - /// deleted: specifically `FreeBalance`. Further, the `OnFreeBalanceZero` callback - /// is invoked, giving a chance to external modules to clean up data associated with - /// the deleted account. + /// deleted: specifically `FreeBalance`. /// /// `system::AccountNonce` is also deleted if `ReservedBalance` is also zero (it also gets /// collapsed to zero if it ever becomes less than `ExistentialDeposit`. diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 3a7be3c84ae25..3d7dcc767897d 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -312,8 +312,7 @@ mod tests { impl pallet_balances::Trait for Runtime { type Balance = u64; - type OnFreeBalanceZero = (); - type OnReapAccount = System; +type OnReapAccount = System; type OnNewAccount = (); type Event = (); type TransferPayment = (); diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index 8eb84d339cc9e..739fe5a4c113d 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -764,8 +764,7 @@ mod tests { impl pallet_balances::Trait for Test { type Balance = u64; type OnNewAccount = (); - type OnFreeBalanceZero = (); - type OnReapAccount = System; +type OnReapAccount = System; type Event = (); type TransferPayment = (); type DustRemoval = (); diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 9bca741fea8bd..5d4a7dc26260f 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -705,8 +705,7 @@ mod tests { } impl pallet_balances::Trait for Test { type Balance = u64; - type OnFreeBalanceZero = (); - type OnReapAccount = System; +type OnReapAccount = System; type OnNewAccount = (); type Event = TestEvent; type TransferPayment = (); diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 560ef19080960..d30e57b99b98c 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -330,8 +330,7 @@ mod tests { } impl pallet_balances::Trait for Test { type Balance = u64; - type OnFreeBalanceZero = (); - type OnReapAccount = System; +type OnReapAccount = System; type OnNewAccount = (); type Event = (); type TransferPayment = (); From e4a965149fcae37f7fba3b9b090cfb8757e830d1 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 23 Jan 2020 16:25:36 +0100 Subject: [PATCH 14/29] Build fixes --- frame/balances/src/lib.rs | 1 - frame/vesting/src/lib.rs | 7 ++++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index d7ccad81f4b39..edddfc87b575a 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -557,7 +557,6 @@ impl, I: Instance> Module { account: &AccountData, old: &AccountData, ) -> UpdateBalanceOutcome { - println!("Setting balance of {:?} to {:?} from {:?}", who, account, Self::account(who)); let total = account.free + account.reserved; if total < T::ExistentialDeposit::get() { T::DustRemoval::on_unbalanced(NegativeImbalance::new(total)); diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index d30e57b99b98c..07bbde3c84406 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -52,9 +52,10 @@ use codec::{Encode, Decode}; use sp_runtime::{DispatchResult, RuntimeDebug, traits::{ StaticLookup, Zero, SimpleArithmetic, MaybeSerializeDeserialize, Saturating, Convert }}; -use frame_support::{decl_module, decl_event, decl_storage, ensure, decl_error, traits::{ +use frame_support::{decl_module, decl_event, decl_storage, ensure, decl_error}; +use frame_support::traits::{ Currency, LockableCurrency, VestingSchedule, WithdrawReason, LockIdentifier -}}; +}; use frame_system::{self as system, ensure_signed}; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -215,7 +216,7 @@ impl Module { let unvested = Self::vesting_balance(&who); if unvested.is_zero() { T::Currency::remove_lock(VESTING_ID, &who); - Vesting::::kill(&who); + Vesting::::remove(&who); Self::deposit_event(RawEvent::VestingCompleted(who)); } else { let reasons = WithdrawReason::Transfer | WithdrawReason::Reserve; From 2603170ded4ea460350294ec2ad638eba004d2f1 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Thu, 23 Jan 2020 16:26:31 +0100 Subject: [PATCH 15/29] Update frame/vesting/src/lib.rs Co-Authored-By: Xiliang Chen --- frame/vesting/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 07bbde3c84406..8e36dbb7ea678 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -107,7 +107,7 @@ impl< } decl_storage! { - trait Store for Module as Sudo { + trait Store for Module as Vesting { /// Information regarding the vesting of a given account. pub Vesting get(fn vesting): map T::AccountId => Option, T::BlockNumber>>; From 16eb4fe23af42876d8ac9d272337c18dcf47da1e Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Thu, 23 Jan 2020 16:26:50 +0100 Subject: [PATCH 16/29] Update frame/vesting/src/lib.rs Co-Authored-By: Xiliang Chen --- frame/vesting/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 8e36dbb7ea678..23d130b5fefc7 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -99,7 +99,7 @@ impl< // Return amount that is still locked in vesting let maybe_balance = vested_block_count.checked_mul(&self.per_block); if let Some(balance) = maybe_balance { - self.locked.max(balance) - balance + self.locked.saturating_sub(balance) } else { Zero::zero() } From 875073dcbcdaa5b9b2ea317b07f0e67cf937d131 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 23 Jan 2020 20:36:51 +0100 Subject: [PATCH 17/29] Migration --- frame/balances/src/lib.rs | 154 ++++++++++++++++++++++++++++++++++---- 1 file changed, 140 insertions(+), 14 deletions(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index edddfc87b575a..2344200b471d4 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -151,15 +151,11 @@ use sp_std::prelude::*; use sp_std::{cmp, result, mem, fmt::Debug, ops::BitOr}; use codec::{Codec, Encode, Decode}; -use frame_support::{ - StorageValue, Parameter, decl_event, decl_storage, decl_module, decl_error, ensure, - traits::{ - UpdateBalanceOutcome, Currency, OnReapAccount, OnUnbalanced, TryDrop, - WithdrawReason, WithdrawReasons, LockIdentifier, LockableCurrency, ExistenceRequirement, - Imbalance, SignedImbalance, ReservableCurrency, Get, - }, - weights::SimpleDispatchInfo, -}; +use frame_support::{StorageValue, Parameter, decl_event, decl_storage, decl_module, decl_error, ensure, traits::{ + UpdateBalanceOutcome, Currency, OnReapAccount, OnUnbalanced, TryDrop, + WithdrawReason, WithdrawReasons, LockIdentifier, LockableCurrency, ExistenceRequirement, + Imbalance, SignedImbalance, ReservableCurrency, Get, +}, weights::SimpleDispatchInfo, Twox128}; use sp_runtime::{ RuntimeDebug, DispatchResult, DispatchError, traits::{ @@ -175,6 +171,8 @@ mod mock; mod tests; pub use self::imbalances::{PositiveImbalance, NegativeImbalance}; +use frame_support::storage::child::kill_storage; +use frame_support::storage::unhashed; pub trait Subtrait: frame_system::Trait { /// The balance of an account. @@ -380,15 +378,10 @@ decl_storage! { .collect::>() ): map T::AccountId => AccountData; - // TODO: Will need to migrate from old FreeBalance, ReservedBalance and the Locks. - // TODO: Will need to migrate from Locks. - /// Any liquidity locks on some account balances. /// NOTE: Should only be accessed when setting, changing and freeing a lock. pub Locks get(fn locks): map T::AccountId => Vec>; - // TODO: Will need to be migrated from the old BalanceLock format on Kusama - /// True if network has been upgraded to this version. IsUpgraded: bool; } @@ -533,12 +526,145 @@ decl_module! { >::transfer(&transactor, &dest, value, ExistenceRequirement::KeepAlive)?; } + fn on_initialize() { + if !IsUpgraded::get() { + IsUgraded()::put(true); + Self::do_upgrade(); + } + } + } +} + +pub struct StorageIterator { + prefix: [u8; 32], + previous_key: Vec, + drain: bool, +} + +impl StorageIterator { + fn new(module: &[u8], item: &[u8]) -> Self { + let mut prefix = [0u8; 32]; + prefix[0..16].copy_from_slice(&Twox128::hash(module)); + prefix[16..32].copy_from_slice(&Twox128::hash(item)); + Self { prefix, previous_key: prefix[..].to_vec(), drain: false } + } + fn drain(mut self) -> Self { + self.drain = true; + self + } +} + +impl Iterator for StorageIterator { + type Item = (Vec, T); + fn next(&mut self) -> Option<(Vec, T)> { + loop { + let maybe_next = sp_io::storage::next_key(&self.previous_key) + .filter(|n| n.starts_with(&self.prefix)); + break match maybe_next { + Some(next) => { + self.previous_key = next; + let maybe_value = frame_support::storage::unhashed::get(&next) + .and_then(|d| T::decode(d).ok()); + match maybe_value { + Some(value) => { + if self.drain { + frame_support::storage::unhashed::kill(&next); + } + Some((self.previous_key[32..].to_vec(), value)) + } + None => continue, + } + } + None => None, + } + } } } +fn get_storage_value(module: &[u8], item: &[u8], hash: &[u8]) -> Option { + let mut key = [0u8; 32 + hash.len()]; + prefix[0..16].copy_from_slice(&Twox128::hash(module)); + prefix[16..32].copy_from_slice(&Twox128::hash(item)); + prefix[32..].copy_from_slice(hash); + frame_support::storage::unhashed::get(&key).and_then(|d| T::decode(d).ok()) +} + +fn put_storage_value(module: &[u8], item: &[u8], hash: &[u8], value: T) { + let mut key = [0u8; 32 + hash.len()]; + prefix[0..16].copy_from_slice(&Twox128::hash(module)); + prefix[16..32].copy_from_slice(&Twox128::hash(item)); + prefix[32..].copy_from_slice(hash); + value.using_encoded(|value| frame_support::storage::unhashed::put(&key, value)); +} + +fn kill_storage_value(module: &[u8], item: &[u8], hash: &[u8]) { + let mut key = [0u8; 32 + hash.len()]; + prefix[0..16].copy_from_slice(&Twox128::hash(module)); + prefix[16..32].copy_from_slice(&Twox128::hash(item)); + prefix[32..].copy_from_slice(hash); + frame_support::storage::unhashed::kill(&key); +} + impl, I: Instance> Module { // PRIVATE MUTABLES + // Upgrade from the pre-#4649 balances/vesting into the new balances. + pub fn do_upgrade() { + // First, migrate from old FreeBalance to new Account. + // We also move all locks across since only accounts with FreeBalance values have locks. + // FreeBalance: map T::AccountId => T::Balance + for (hash, free) in storage_drainer::(b"Balances", b"FreeBalance").drain() { + let mut account = AccountData { free, ..Default::default() }; + // Locks: map T::AccountId => Vec + struct BalanceLock { + id: LockIdentifier, + amount: T::Balance, + until: T::BlockNumber, + reasons: WithdrawReasons, + } + let old_locks = get_storage_value::>(b"Balances", b"Locks", hash); + if let Some(locks) = old_locks { + let locks = locks.into_iter().map(Into::into).collect::>(); + for l in locks.iter() { + if l.reasons == Reasons::All || l.reasons == Reasons::Misc { + account.misc_frozen = account.misc_frozen.max(l.amount); + } + if l.reasons == Reasons::All || l.reasons == Reasons::Fee { + account.fee_frozen = account.fee_frozen.max(l.amount); + } + } + put_storage_value(b"Balances", b"Locks", &hash, locks); + } + put_storage_value(b"Balances", b"Account", &hash, account); + } + // Second, migrate old ReservedBalance into new Account. + // ReservedBalance: map T::AccountId => T::Balance + for (hash, reserved) in storage_drainer::(b"Balances", b"ReservedBalance").drain() { + let mut account = get_storage_value::>(b"Balances", b"Account", hash).unwrap_or_default(); + account.reserved = reserved; + put_storage_value(b"Balances", b"Account", hash, account); + } + + // Finally, migrate vesting and ensure locks are in place. We will be lazy and just lock + // for the maximum amount (i.e. at genesis). Users will need to call "vest" to reduce the + // lock to something sensible. + // pub Vesting: map T::AccountId => Option; + struct VestingSchedule { + locked: T::Balance, + per_block: T::Balance, + starting_block: T::BlockNumber, + } + for (hash, vesting) in storage_drainer::(b"Balances", b"Vesting").drain() { + let mut account = get_storage_value::>(b"Balances", b"Account", hash).unwrap_or_default(); + account.locks.push(BalanceLock { + id: *b"vesting ", + amount: locked, + reasons: WithdrawReason::Transfer | WithdrawReason::Reserve, + }); + put_storage_value(b"Vesting", b"Account", hash, vesting); + put_storage_value(b"Balances", b"Account", hash, account); + } + } /// Set both the free and reserved balance of an account to some new value. Will enforce /// `ExistentialDeposit` law, annulling the account as needed. /// From 99d86e8e7b5d4767cf4edbac0c41e0d6ebe86056 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 24 Jan 2020 00:20:26 +0100 Subject: [PATCH 18/29] Remove superfluous code. --- frame/balances/Cargo.toml | 4 +- frame/balances/src/lib.rs | 117 +++++++++++++++++++++++--------------- frame/support/src/lib.rs | 3 +- frame/vesting/src/lib.rs | 23 ++++---- 4 files changed, 87 insertions(+), 60 deletions(-) diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index f9522b5379ff5..22f377c155eac 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" serde = { version = "1.0.101", optional = true } codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } sp-std = { version = "2.0.0", default-features = false, path = "../../primitives/std" } +sp-io = { version = "2.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "2.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "2.0.0", default-features = false, path = "../support" } frame-system = { version = "2.0.0", default-features = false, path = "../system" } @@ -23,7 +24,8 @@ std = [ "serde", "codec/std", "sp-std/std", - "frame-support/std", + "sp-io/std", "sp-runtime/std", + "frame-support/std", "frame-system/std", ] diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 2344200b471d4..e55ca3b189a8e 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -171,8 +171,6 @@ mod mock; mod tests; pub use self::imbalances::{PositiveImbalance, NegativeImbalance}; -use frame_support::storage::child::kill_storage; -use frame_support::storage::unhashed; pub trait Subtrait: frame_system::Trait { /// The balance of an account. @@ -527,8 +525,8 @@ decl_module! { } fn on_initialize() { - if !IsUpgraded::get() { - IsUgraded()::put(true); + if !IsUpgraded::::get() { + IsUpgraded::::put(true); Self::do_upgrade(); } } @@ -539,14 +537,17 @@ pub struct StorageIterator { prefix: [u8; 32], previous_key: Vec, drain: bool, + _phantom: ::sp_std::marker::PhantomData, } +use frame_support::StorageHasher; + impl StorageIterator { fn new(module: &[u8], item: &[u8]) -> Self { let mut prefix = [0u8; 32]; prefix[0..16].copy_from_slice(&Twox128::hash(module)); prefix[16..32].copy_from_slice(&Twox128::hash(item)); - Self { prefix, previous_key: prefix[..].to_vec(), drain: false } + Self { prefix, previous_key: prefix[..].to_vec(), drain: false, _phantom: Default::default() } } fn drain(mut self) -> Self { self.drain = true; @@ -554,7 +555,7 @@ impl StorageIterator { } } -impl Iterator for StorageIterator { +impl Iterator for StorageIterator { type Item = (Vec, T); fn next(&mut self) -> Option<(Vec, T)> { loop { @@ -562,9 +563,8 @@ impl Iterator for StorageIterator { .filter(|n| n.starts_with(&self.prefix)); break match maybe_next { Some(next) => { - self.previous_key = next; - let maybe_value = frame_support::storage::unhashed::get(&next) - .and_then(|d| T::decode(d).ok()); + self.previous_key = next.clone(); + let maybe_value = frame_support::storage::unhashed::get::(&next); match maybe_value { Some(value) => { if self.drain { @@ -581,50 +581,74 @@ impl Iterator for StorageIterator { } } -fn get_storage_value(module: &[u8], item: &[u8], hash: &[u8]) -> Option { - let mut key = [0u8; 32 + hash.len()]; - prefix[0..16].copy_from_slice(&Twox128::hash(module)); - prefix[16..32].copy_from_slice(&Twox128::hash(item)); - prefix[32..].copy_from_slice(hash); - frame_support::storage::unhashed::get(&key).and_then(|d| T::decode(d).ok()) +fn get_storage_value(module: &[u8], item: &[u8], hash: &[u8]) -> Option { + let mut key = vec![0u8; 32 + hash.len()]; + key[0..16].copy_from_slice(&Twox128::hash(module)); + key[16..32].copy_from_slice(&Twox128::hash(item)); + key[32..].copy_from_slice(hash); + frame_support::storage::unhashed::get::(&key) } fn put_storage_value(module: &[u8], item: &[u8], hash: &[u8], value: T) { - let mut key = [0u8; 32 + hash.len()]; - prefix[0..16].copy_from_slice(&Twox128::hash(module)); - prefix[16..32].copy_from_slice(&Twox128::hash(item)); - prefix[32..].copy_from_slice(hash); + let mut key = vec![0u8; 32 + hash.len()]; + key[0..16].copy_from_slice(&Twox128::hash(module)); + key[16..32].copy_from_slice(&Twox128::hash(item)); + key[32..].copy_from_slice(hash); value.using_encoded(|value| frame_support::storage::unhashed::put(&key, value)); } fn kill_storage_value(module: &[u8], item: &[u8], hash: &[u8]) { - let mut key = [0u8; 32 + hash.len()]; - prefix[0..16].copy_from_slice(&Twox128::hash(module)); - prefix[16..32].copy_from_slice(&Twox128::hash(item)); - prefix[32..].copy_from_slice(hash); + let mut key = vec![0u8; 32 + hash.len()]; + key[0..16].copy_from_slice(&Twox128::hash(module)); + key[16..32].copy_from_slice(&Twox128::hash(item)); + key[32..].copy_from_slice(hash); frame_support::storage::unhashed::kill(&key); } +#[derive(Decode)] +struct OldBalanceLock { + id: LockIdentifier, + amount: Balance, + until: BlockNumber, + reasons: WithdrawReasons, +} + +impl OldBalanceLock { + fn upgraded(self) -> (BalanceLock, BlockNumber) { + (BalanceLock { + id: self.id, + amount: self.amount, + reasons: self.reasons.into(), + }, self.until) + } +} + impl, I: Instance> Module { // PRIVATE MUTABLES // Upgrade from the pre-#4649 balances/vesting into the new balances. pub fn do_upgrade() { + // TODO: Handle Instance parameter in storage access. // First, migrate from old FreeBalance to new Account. // We also move all locks across since only accounts with FreeBalance values have locks. // FreeBalance: map T::AccountId => T::Balance - for (hash, free) in storage_drainer::(b"Balances", b"FreeBalance").drain() { + for (hash, free) in StorageIterator::::new(b"Balances", b"FreeBalance").drain() { let mut account = AccountData { free, ..Default::default() }; // Locks: map T::AccountId => Vec - struct BalanceLock { - id: LockIdentifier, - amount: T::Balance, - until: T::BlockNumber, - reasons: WithdrawReasons, - } - let old_locks = get_storage_value::>(b"Balances", b"Locks", hash); + let old_locks = get_storage_value::>>(b"Balances", b"Locks", &hash); if let Some(locks) = old_locks { - let locks = locks.into_iter().map(Into::into).collect::>(); + let locks = locks.into_iter() + .map(|i| { + let (result, expiry) = i.upgraded(); + if expiry != T::BlockNumber::max_value() { + // Any `until`s that are not T::BlockNumber::max_value come from + // democracy and need to be migrated over there. + // Democracy: Locks get(locks): map T::AccountId => Option; + put_storage_value(b"Democracy", b"Locks", &hash, expiry); + } + result + }) + .collect::>(); for l in locks.iter() { if l.reasons == Reasons::All || l.reasons == Reasons::Misc { account.misc_frozen = account.misc_frozen.max(l.amount); @@ -639,32 +663,31 @@ impl, I: Instance> Module { } // Second, migrate old ReservedBalance into new Account. // ReservedBalance: map T::AccountId => T::Balance - for (hash, reserved) in storage_drainer::(b"Balances", b"ReservedBalance").drain() { - let mut account = get_storage_value::>(b"Balances", b"Account", hash).unwrap_or_default(); + for (hash, reserved) in StorageIterator::::new(b"Balances", b"ReservedBalance").drain() { + let mut account = get_storage_value::>(b"Balances", b"Account", &hash).unwrap_or_default(); account.reserved = reserved; - put_storage_value(b"Balances", b"Account", hash, account); + put_storage_value(b"Balances", b"Account", &hash, account); } // Finally, migrate vesting and ensure locks are in place. We will be lazy and just lock // for the maximum amount (i.e. at genesis). Users will need to call "vest" to reduce the // lock to something sensible. // pub Vesting: map T::AccountId => Option; - struct VestingSchedule { - locked: T::Balance, - per_block: T::Balance, - starting_block: T::BlockNumber, - } - for (hash, vesting) in storage_drainer::(b"Balances", b"Vesting").drain() { - let mut account = get_storage_value::>(b"Balances", b"Account", hash).unwrap_or_default(); - account.locks.push(BalanceLock { + for (hash, vesting) in StorageIterator::<(T::Balance, T::Balance, T::BlockNumber)>::new(b"Balances", b"Vesting").drain() { + let mut account = get_storage_value::>(b"Balances", b"Account", &hash).unwrap_or_default(); + let mut locks = get_storage_value::>>(b"Balances", b"Locks", &hash).unwrap_or_default(); + locks.push(BalanceLock { id: *b"vesting ", - amount: locked, - reasons: WithdrawReason::Transfer | WithdrawReason::Reserve, + amount: vesting.0.clone(), + reasons: Reasons::Misc, }); - put_storage_value(b"Vesting", b"Account", hash, vesting); - put_storage_value(b"Balances", b"Account", hash, account); + account.misc_frozen = account.misc_frozen.max(vesting.0.clone()); + put_storage_value(b"Vesting", b"Vesting", &hash, vesting); + put_storage_value(b"Balances", b"Locks", &hash, locks); + put_storage_value(b"Balances", b"Account", &hash, account); } } + /// Set both the free and reserved balance of an account to some new value. Will enforce /// `ExistentialDeposit` law, annulling the account as needed. /// diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index ebfc7bbe97ebe..fa1684b2c83cb 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -67,7 +67,8 @@ pub mod traits; pub mod weights; pub use self::hash::{ - Twox256, Twox128, Blake2_256, Blake2_128, Twox64Concat, Blake2_128Concat, Hashable + Twox256, Twox128, Blake2_256, Blake2_128, Twox64Concat, Blake2_128Concat, Hashable, + StorageHasher }; pub use self::storage::{ StorageValue, StorageMap, StorageLinkedMap, StorageDoubleMap, StoragePrefixedMap diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 23d130b5fefc7..4da5c26a3e08f 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -65,7 +65,7 @@ pub trait Trait: frame_system::Trait { type Event: From> + Into<::Event>; /// The currency trait. - type Currency: Currency + LockableCurrency; + type Currency: LockableCurrency; /// Convert the block number into a balance. type BlockNumberToBalance: Convert>; @@ -182,7 +182,7 @@ decl_module! { /// # fn vest(origin) -> DispatchResult { let who = ensure_signed(origin)?; - Self::unlock_vested(who) + Self::update_lock(who) } /// Unlock any vested funds of a `target` account. @@ -203,7 +203,7 @@ decl_module! { /// # fn vest_other(origin, target: ::Source) -> DispatchResult { ensure_signed(origin)?; - Self::unlock_vested(T::Lookup::lookup(target)?) + Self::update_lock(T::Lookup::lookup(target)?) } } } @@ -211,7 +211,7 @@ decl_module! { impl Module { /// (Re)set or remove the module's currency lock on `who`'s account in accordance with their /// current unvested amount. - fn unlock_vested(who: T::AccountId) -> DispatchResult { + fn update_lock(who: T::AccountId) -> DispatchResult { ensure!(Vesting::::exists(&who), Error::::NotVesting); let unvested = Self::vesting_balance(&who); if unvested.is_zero() { @@ -257,7 +257,7 @@ impl VestingSchedule for Module where starting_block: T::BlockNumber ) -> DispatchResult { if locked.is_zero() { return Ok(()) } - if >::exists(who) { + if Vesting::::exists(who) { Err(Error::::ExistingVestingSchedule)? } let vesting_schedule = VestingInfo { @@ -265,13 +265,17 @@ impl VestingSchedule for Module where per_block, starting_block }; - >::insert(who, vesting_schedule); + Vesting::::insert(who, vesting_schedule); + // it can't fail, but even if somehow it did, we don't really care. + let _ = Self::update_lock(who.clone()); Ok(()) } /// Remove a vesting schedule for a given account. fn remove_vesting_schedule(who: &T::AccountId) { - >::remove(who); + Vesting::::remove(who); + // it can't fail, but even if somehow it did, we don't really care. + let _ = Self::update_lock(who.clone()); } } @@ -280,13 +284,10 @@ mod tests { use super::*; use std::cell::RefCell; - use sp_runtime::traits::BadOrigin; use frame_support::{ - assert_ok, assert_noop, impl_outer_origin, parameter_types, weights::Weight, - ord_parameter_types, traits::Get + assert_ok, assert_noop, impl_outer_origin, parameter_types, weights::Weight, traits::Get }; use sp_core::H256; - use frame_system::EnsureSignedBy; // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. use sp_runtime::{ From 4827931417ba1c323494f53229c2293f02d516d7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 24 Jan 2020 00:49:47 +0100 Subject: [PATCH 19/29] Test fixes --- frame/identity/src/lib.rs | 26 +++++++-------- frame/recovery/src/tests.rs | 12 +++---- frame/utility/src/lib.rs | 64 ++++++++++++++++++------------------- 3 files changed, 51 insertions(+), 51 deletions(-) diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index f6013c93d0ac8..a6eec63230246 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -1007,9 +1007,9 @@ type OnReapAccount = System; assert_ok!(Identity::set_fee(Origin::signed(3), 0, 10)); assert_ok!(Identity::set_identity(Origin::signed(10), ten())); assert_eq!(Identity::identity(10).unwrap().info, ten()); - assert_eq!(Balances::free_balance(10), 90); + assert_eq!(Balances::free_balance(&10), 90); assert_ok!(Identity::clear_identity(Origin::signed(10))); - assert_eq!(Balances::free_balance(10), 100); + assert_eq!(Balances::free_balance(&10), 100); assert_noop!(Identity::clear_identity(Origin::signed(10)), Error::::NotNamed); }); } @@ -1061,7 +1061,7 @@ type OnReapAccount = System; assert_noop!(Identity::kill_identity(Origin::signed(1), 10), BadOrigin); assert_ok!(Identity::kill_identity(Origin::signed(2), 10)); assert_eq!(Identity::identity(10), None); - assert_eq!(Balances::free_balance(10), 90); + assert_eq!(Balances::free_balance(&10), 90); assert_noop!(Identity::kill_identity(Origin::signed(2), 10), Error::::NotNamed); }); } @@ -1074,14 +1074,14 @@ type OnReapAccount = System; assert_ok!(Identity::set_identity(Origin::signed(10), ten())); assert_ok!(Identity::set_subs(Origin::signed(10), subs.clone())); - assert_eq!(Balances::free_balance(10), 80); + assert_eq!(Balances::free_balance(&10), 80); assert_eq!(Identity::subs(10), (10, vec![20])); assert_eq!(Identity::super_of(20), Some((10, Data::Raw(vec![40; 1])))); // push another item and re-set it. subs.push((30, Data::Raw(vec![50; 1]))); assert_ok!(Identity::set_subs(Origin::signed(10), subs.clone())); - assert_eq!(Balances::free_balance(10), 70); + assert_eq!(Balances::free_balance(&10), 70); assert_eq!(Identity::subs(10), (20, vec![20, 30])); assert_eq!(Identity::super_of(20), Some((10, Data::Raw(vec![40; 1])))); assert_eq!(Identity::super_of(30), Some((10, Data::Raw(vec![50; 1])))); @@ -1089,7 +1089,7 @@ type OnReapAccount = System; // switch out one of the items and re-set. subs[0] = (40, Data::Raw(vec![60; 1])); assert_ok!(Identity::set_subs(Origin::signed(10), subs.clone())); - assert_eq!(Balances::free_balance(10), 70); // no change in the balance + assert_eq!(Balances::free_balance(&10), 70); // no change in the balance assert_eq!(Identity::subs(10), (20, vec![40, 30])); assert_eq!(Identity::super_of(20), None); assert_eq!(Identity::super_of(30), Some((10, Data::Raw(vec![50; 1])))); @@ -1097,7 +1097,7 @@ type OnReapAccount = System; // clear assert_ok!(Identity::set_subs(Origin::signed(10), vec![])); - assert_eq!(Balances::free_balance(10), 90); + assert_eq!(Balances::free_balance(&10), 90); assert_eq!(Identity::subs(10), (0, vec![])); assert_eq!(Identity::super_of(30), None); assert_eq!(Identity::super_of(40), None); @@ -1113,7 +1113,7 @@ type OnReapAccount = System; assert_ok!(Identity::set_identity(Origin::signed(10), ten())); assert_ok!(Identity::set_subs(Origin::signed(10), vec![(20, Data::Raw(vec![40; 1]))])); assert_ok!(Identity::clear_identity(Origin::signed(10))); - assert_eq!(Balances::free_balance(10), 100); + assert_eq!(Balances::free_balance(&10), 100); assert!(Identity::super_of(20).is_none()); }); } @@ -1124,7 +1124,7 @@ type OnReapAccount = System; assert_ok!(Identity::set_identity(Origin::signed(10), ten())); assert_ok!(Identity::set_subs(Origin::signed(10), vec![(20, Data::Raw(vec![40; 1]))])); assert_ok!(Identity::kill_identity(Origin::ROOT, 10)); - assert_eq!(Balances::free_balance(10), 80); + assert_eq!(Balances::free_balance(&10), 80); assert!(Identity::super_of(20).is_none()); }); } @@ -1138,7 +1138,7 @@ type OnReapAccount = System; assert_ok!(Identity::set_identity(Origin::signed(10), ten())); assert_ok!(Identity::request_judgement(Origin::signed(10), 0, 10)); assert_ok!(Identity::cancel_request(Origin::signed(10), 0)); - assert_eq!(Balances::free_balance(10), 90); + assert_eq!(Balances::free_balance(&10), 90); assert_noop!(Identity::cancel_request(Origin::signed(10), 0), Error::::NotFound); assert_ok!(Identity::provide_judgement(Origin::signed(3), 0, 10, Judgement::Reasonable)); @@ -1155,13 +1155,13 @@ type OnReapAccount = System; assert_noop!(Identity::request_judgement(Origin::signed(10), 0, 9), Error::::FeeChanged); assert_ok!(Identity::request_judgement(Origin::signed(10), 0, 10)); // 10 for the judgement request, 10 for the identity. - assert_eq!(Balances::free_balance(10), 80); + assert_eq!(Balances::free_balance(&10), 80); // Re-requesting won't work as we already paid. assert_noop!(Identity::request_judgement(Origin::signed(10), 0, 10), Error::::StickyJudgement); assert_ok!(Identity::provide_judgement(Origin::signed(3), 0, 10, Judgement::Erroneous)); // Registrar got their payment now. - assert_eq!(Balances::free_balance(3), 20); + assert_eq!(Balances::free_balance(&3), 20); // Re-requesting still won't work as it's erroneous. assert_noop!(Identity::request_judgement(Origin::signed(10), 0, 10), Error::::StickyJudgement); @@ -1187,7 +1187,7 @@ type OnReapAccount = System; (Data::Raw(b"text".to_vec()), Data::Raw(b"10".to_vec())), ], .. Default::default() })); - assert_eq!(Balances::free_balance(10), 70); + assert_eq!(Balances::free_balance(&10), 70); }); } diff --git a/frame/recovery/src/tests.rs b/frame/recovery/src/tests.rs index 76f05156ef5c6..c9586dce849fe 100644 --- a/frame/recovery/src/tests.rs +++ b/frame/recovery/src/tests.rs @@ -50,8 +50,8 @@ fn set_recovered_works() { let call = Box::new(Call::Balances(BalancesCall::transfer(1, 100))); assert_ok!(Recovery::as_recovered(Origin::signed(1), 5, call)); // Account 1 has successfully drained the funds from account 5 - assert_eq!(Balances::free_balance(1), 200); - assert_eq!(Balances::free_balance(5), 0); + assert_eq!(Balances::free_balance(&1), 200); + assert_eq!(Balances::free_balance(&5), 0); }); } @@ -85,12 +85,12 @@ fn recovery_lifecycle_works() { let call = Box::new(Call::Recovery(RecoveryCall::remove_recovery())); assert_ok!(Recovery::as_recovered(Origin::signed(1), 5, call)); // Account 1 should now be able to make a call through account 5 to get all of their funds - assert_eq!(Balances::free_balance(5), 110); + assert_eq!(Balances::free_balance(&5), 110); let call = Box::new(Call::Balances(BalancesCall::transfer(1, 110))); assert_ok!(Recovery::as_recovered(Origin::signed(1), 5, call)); // All funds have been fully recovered! - assert_eq!(Balances::free_balance(1), 200); - assert_eq!(Balances::free_balance(5), 0); + assert_eq!(Balances::free_balance(&1), 200); + assert_eq!(Balances::free_balance(&5), 0); // All storage items are removed from the module assert!(!>::exists(&5, &1)); assert!(!>::exists(&5)); @@ -190,7 +190,7 @@ fn create_recovery_works() { assert_ok!(Recovery::create_recovery(Origin::signed(5), friends.clone(), threshold, delay_period)); // Deposit is taken, and scales with the number of friends they pick // Base 10 + 1 per friends = 13 total reserved - assert_eq!(Balances::reserved_balance(5), 13); + assert_eq!(Balances::reserved_balance(&5), 13); // Recovery configuration is correctly stored let recovery_config = RecoveryConfig { delay_period, diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 5d4a7dc26260f..d78203672adff 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -763,12 +763,12 @@ type OnReapAccount = System; let call = Box::new(Call::Balances(BalancesCall::transfer(6, 15))); assert_ok!(Utility::as_multi(Origin::signed(1), 2, vec![2, 3], None, call.clone())); - assert_eq!(Balances::free_balance(1), 2); - assert_eq!(Balances::reserved_balance(1), 3); + assert_eq!(Balances::free_balance(&1), 2); + assert_eq!(Balances::reserved_balance(&1), 3); assert_ok!(Utility::as_multi(Origin::signed(2), 2, vec![1, 3], Some(now()), call)); - assert_eq!(Balances::free_balance(1), 5); - assert_eq!(Balances::reserved_balance(1), 0); + assert_eq!(Balances::free_balance(&1), 5); + assert_eq!(Balances::reserved_balance(&1), 0); }); } @@ -779,13 +779,13 @@ type OnReapAccount = System; let hash = call.using_encoded(blake2_256); assert_ok!(Utility::approve_as_multi(Origin::signed(1), 3, vec![2, 3], None, hash.clone())); assert_ok!(Utility::approve_as_multi(Origin::signed(2), 3, vec![1, 3], Some(now()), hash.clone())); - assert_eq!(Balances::free_balance(1), 6); - assert_eq!(Balances::reserved_balance(1), 4); + assert_eq!(Balances::free_balance(&1), 6); + assert_eq!(Balances::reserved_balance(&1), 4); assert_ok!( Utility::cancel_as_multi(Origin::signed(1), 3, vec![2, 3], now(), hash.clone()), ); - assert_eq!(Balances::free_balance(1), 10); - assert_eq!(Balances::reserved_balance(1), 0); + assert_eq!(Balances::free_balance(&1), 10); + assert_eq!(Balances::reserved_balance(&1), 0); }); } @@ -830,10 +830,10 @@ type OnReapAccount = System; let call = Box::new(Call::Balances(BalancesCall::transfer(6, 15))); let hash = call.using_encoded(blake2_256); assert_ok!(Utility::approve_as_multi(Origin::signed(1), 2, vec![2, 3], None, hash)); - assert_eq!(Balances::free_balance(6), 0); + assert_eq!(Balances::free_balance(&6), 0); assert_ok!(Utility::as_multi(Origin::signed(2), 2, vec![1, 3], Some(now()), call)); - assert_eq!(Balances::free_balance(6), 15); + assert_eq!(Balances::free_balance(&6), 15); }); } @@ -849,10 +849,10 @@ type OnReapAccount = System; let hash = call.using_encoded(blake2_256); assert_ok!(Utility::approve_as_multi(Origin::signed(1), 3, vec![2, 3], None, hash.clone())); assert_ok!(Utility::approve_as_multi(Origin::signed(2), 3, vec![1, 3], Some(now()), hash.clone())); - assert_eq!(Balances::free_balance(6), 0); + assert_eq!(Balances::free_balance(&6), 0); assert_ok!(Utility::as_multi(Origin::signed(3), 3, vec![1, 2], Some(now()), call)); - assert_eq!(Balances::free_balance(6), 15); + assert_eq!(Balances::free_balance(&6), 15); }); } @@ -883,10 +883,10 @@ type OnReapAccount = System; let call = Box::new(Call::Balances(BalancesCall::transfer(6, 15))); assert_ok!(Utility::as_multi(Origin::signed(1), 2, vec![2, 3], None, call.clone())); - assert_eq!(Balances::free_balance(6), 0); + assert_eq!(Balances::free_balance(&6), 0); assert_ok!(Utility::as_multi(Origin::signed(2), 2, vec![1, 3], Some(now()), call)); - assert_eq!(Balances::free_balance(6), 15); + assert_eq!(Balances::free_balance(&6), 15); }); } @@ -906,8 +906,8 @@ type OnReapAccount = System; assert_ok!(Utility::as_multi(Origin::signed(3), 2, vec![1, 2], Some(now()), call2)); assert_ok!(Utility::as_multi(Origin::signed(3), 2, vec![1, 2], Some(now()), call1)); - assert_eq!(Balances::free_balance(6), 10); - assert_eq!(Balances::free_balance(7), 5); + assert_eq!(Balances::free_balance(&6), 10); + assert_eq!(Balances::free_balance(&7), 5); }); } @@ -922,7 +922,7 @@ type OnReapAccount = System; let call = Box::new(Call::Balances(BalancesCall::transfer(6, 10))); assert_ok!(Utility::as_multi(Origin::signed(1), 2, vec![2, 3], None, call.clone())); assert_ok!(Utility::as_multi(Origin::signed(2), 2, vec![1, 3], Some(now()), call.clone())); - assert_eq!(Balances::free_balance(multi), 5); + assert_eq!(Balances::free_balance(&multi), 5); assert_ok!(Utility::as_multi(Origin::signed(1), 2, vec![2, 3], None, call.clone())); assert_ok!(Utility::as_multi(Origin::signed(3), 2, vec![1, 2], Some(now()), call)); @@ -992,7 +992,7 @@ type OnReapAccount = System; ); assert_ok!(Utility::as_multi(Origin::signed(1), 1, vec![2, 3], None, call)); - assert_eq!(Balances::free_balance(6), 15); + assert_eq!(Balances::free_balance(&6), 15); }); } @@ -1011,46 +1011,46 @@ type OnReapAccount = System; 0, Box::new(Call::Balances(BalancesCall::transfer(2, 3))), )); - assert_eq!(Balances::free_balance(sub_1_0), 2); - assert_eq!(Balances::free_balance(2), 13); + assert_eq!(Balances::free_balance(&sub_1_0), 2); + assert_eq!(Balances::free_balance(&2), 13); }); } #[test] fn batch_with_root_works() { new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(1), 10); - assert_eq!(Balances::free_balance(2), 10); + assert_eq!(Balances::free_balance(&1), 10); + assert_eq!(Balances::free_balance(&2), 10); assert_ok!(Utility::batch(Origin::ROOT, vec![ Call::Balances(BalancesCall::force_transfer(1, 2, 5)), Call::Balances(BalancesCall::force_transfer(1, 2, 5)) ])); - assert_eq!(Balances::free_balance(1), 0); - assert_eq!(Balances::free_balance(2), 20); + assert_eq!(Balances::free_balance(&1), 0); + assert_eq!(Balances::free_balance(&2), 20); }); } #[test] fn batch_with_signed_works() { new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(1), 10); - assert_eq!(Balances::free_balance(2), 10); + assert_eq!(Balances::free_balance(&1), 10); + assert_eq!(Balances::free_balance(&2), 10); assert_ok!( Utility::batch(Origin::signed(1), vec![ Call::Balances(BalancesCall::transfer(2, 5)), Call::Balances(BalancesCall::transfer(2, 5)) ]), ); - assert_eq!(Balances::free_balance(1), 0); - assert_eq!(Balances::free_balance(2), 20); + assert_eq!(Balances::free_balance(&1), 0); + assert_eq!(Balances::free_balance(&2), 20); }); } #[test] fn batch_early_exit_works() { new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(1), 10); - assert_eq!(Balances::free_balance(2), 10); + assert_eq!(Balances::free_balance(&1), 10); + assert_eq!(Balances::free_balance(&2), 10); assert_ok!( Utility::batch(Origin::signed(1), vec![ Call::Balances(BalancesCall::transfer(2, 5)), @@ -1058,8 +1058,8 @@ type OnReapAccount = System; Call::Balances(BalancesCall::transfer(2, 5)), ]), ); - assert_eq!(Balances::free_balance(1), 5); - assert_eq!(Balances::free_balance(2), 15); + assert_eq!(Balances::free_balance(&1), 5); + assert_eq!(Balances::free_balance(&2), 15); }); } } From 21687ddba1dc150af41d8220d5cbf7ab13dc9dbd Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 24 Jan 2020 16:59:24 +0100 Subject: [PATCH 20/29] Fix some tests --- bin/node/executor/tests/basic.rs | 47 ++++++++------- bin/node/executor/tests/fees.rs | 14 ++--- bin/node/executor/tests/submit_transaction.rs | 3 +- frame/balances/src/lib.rs | 19 ++++-- frame/democracy/src/lib.rs | 33 +++++----- frame/elections/src/mock.rs | 3 +- frame/executive/src/lib.rs | 2 +- frame/society/src/tests.rs | 60 +++++++++---------- frame/transaction-payment/src/lib.rs | 4 +- 9 files changed, 96 insertions(+), 89 deletions(-) diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index 817ebbb173933..b306852f4547d 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -35,8 +35,7 @@ use frame_system::{self, EventRecord, Phase}; use node_runtime::{ Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Call, Runtime, Balances, - System, TransactionPayment, Event, - TransferFee, TransactionBaseFee, TransactionByteFee, + System, TransactionPayment, Event, TransactionBaseFee, TransactionByteFee, CreationFee, constants::currency::*, }; use node_primitives::{Balance, Hash}; @@ -62,7 +61,7 @@ fn transfer_fee(extrinsic: &E, fee_multiplier: Fixed64) -> Balance { ::WeightToFee::convert(weight); let base_fee = TransactionBaseFee::get(); - base_fee + fee_multiplier.saturated_multiply_accumulate(length_fee + weight_fee) + TransferFee::get() + base_fee + fee_multiplier.saturated_multiply_accumulate(length_fee + weight_fee) } fn xt() -> UncheckedExtrinsic { @@ -164,8 +163,8 @@ fn block_with_size(time: u64, nonce: u32, size: usize) -> (Vec, Hash) { fn panic_execution_with_foreign_code_gives_error() { let mut t = TestExternalities::::new_with_code(BLOATY_CODE, Storage { top: map![ - >::hashed_key_for(alice()) => { - 69_u128.encode() + >::hashed_key_for(alice()) => { + (69u128, 0u128, 0u128, 0u128).encode() }, >::hashed_key().to_vec() => { 69_u128.encode() @@ -203,8 +202,8 @@ fn panic_execution_with_foreign_code_gives_error() { fn bad_extrinsic_with_native_equivalent_code_gives_error() { let mut t = TestExternalities::::new_with_code(COMPACT_CODE, Storage { top: map![ - >::hashed_key_for(alice()) => { - 69_u128.encode() + >::hashed_key_for(alice()) => { + (69u128, 0u128, 0u128, 0u128).encode() }, >::hashed_key().to_vec() => { 69_u128.encode() @@ -242,8 +241,8 @@ fn bad_extrinsic_with_native_equivalent_code_gives_error() { fn successful_execution_with_native_equivalent_code_gives_ok() { let mut t = TestExternalities::::new_with_code(COMPACT_CODE, Storage { top: map![ - >::hashed_key_for(alice()) => { - (111 * DOLLARS).encode() + >::hashed_key_for(alice()) => { + (111 * DOLLARS, 0u128, 0u128, 0u128).encode() }, >::hashed_key().to_vec() => { (111 * DOLLARS).encode() @@ -275,7 +274,8 @@ fn successful_execution_with_native_equivalent_code_gives_ok() { assert!(r.is_ok()); t.execute_with(|| { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt(), fm)); + let fees = transfer_fee(&xt(), fm) + CreationFee::get(); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } @@ -284,8 +284,8 @@ fn successful_execution_with_native_equivalent_code_gives_ok() { fn successful_execution_with_foreign_code_gives_ok() { let mut t = TestExternalities::::new_with_code(BLOATY_CODE, Storage { top: map![ - >::hashed_key_for(alice()) => { - (111 * DOLLARS).encode() + >::hashed_key_for(alice()) => { + (111 * DOLLARS, 0u128, 0u128, 0u128).encode() }, >::hashed_key().to_vec() => { (111 * DOLLARS).encode() @@ -317,7 +317,8 @@ fn successful_execution_with_foreign_code_gives_ok() { assert!(r.is_ok()); t.execute_with(|| { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt(), fm)); + let fees = transfer_fee(&xt(), fm) + CreationFee::get(); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } @@ -340,7 +341,8 @@ fn full_native_block_import_works() { ).0.unwrap(); t.execute_with(|| { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt(), fm)); + let fees = transfer_fee(&xt(), fm); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS); alice_last_known_balance = Balances::total_balance(&alice()); let events = vec![ @@ -362,7 +364,7 @@ fn full_native_block_import_works() { alice().into(), bob().into(), 69 * DOLLARS, - 1 * CENTS, + 0, )), topics: vec![], }, @@ -416,7 +418,7 @@ fn full_native_block_import_works() { bob().into(), alice().into(), 5 * DOLLARS, - 1 * CENTS, + 0, ) ), topics: vec![], @@ -440,7 +442,7 @@ fn full_native_block_import_works() { alice().into(), bob().into(), 15 * DOLLARS, - 1 * CENTS, + 0, ) ), topics: vec![], @@ -710,8 +712,8 @@ fn native_big_block_import_fails_on_fallback() { fn panic_execution_gives_error() { let mut t = TestExternalities::::new_with_code(BLOATY_CODE, Storage { top: map![ - >::hashed_key_for(alice()) => { - 0_u128.encode() + >::hashed_key_for(alice()) => { + (0_u128, 0_u128, 0_u128, 0_u128).encode() }, >::hashed_key().to_vec() => { 0_u128.encode() @@ -745,8 +747,8 @@ fn panic_execution_gives_error() { fn successful_execution_gives_ok() { let mut t = TestExternalities::::new_with_code(COMPACT_CODE, Storage { top: map![ - >::hashed_key_for(alice()) => { - (111 * DOLLARS).encode() + >::hashed_key_for(alice()) => { + (111 * DOLLARS, 0u128, 0u128, 0u128).encode() }, >::hashed_key().to_vec() => { (111 * DOLLARS).encode() @@ -779,7 +781,8 @@ fn successful_execution_gives_ok() { .expect("Extrinsic did not fail"); t.execute_with(|| { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * transfer_fee(&xt(), fm)); + let fees = transfer_fee(&xt(), fm) + CreationFee::get(); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } diff --git a/bin/node/executor/tests/fees.rs b/bin/node/executor/tests/fees.rs index ca34452031780..155cefa4ccada 100644 --- a/bin/node/executor/tests/fees.rs +++ b/bin/node/executor/tests/fees.rs @@ -30,7 +30,7 @@ use sp_runtime::{ }; use node_runtime::{ CheckedExtrinsic, Call, Runtime, Balances, - TransactionPayment, TransferFee, TransactionBaseFee, TransactionByteFee, + TransactionPayment, TransactionBaseFee, TransactionByteFee, WeightFeeCoefficient, constants::currency::*, }; use node_runtime::impls::LinearWeightToFee; @@ -134,14 +134,14 @@ fn transaction_fee_is_correct_ultimate() { // (this baed on assigning 0.1 CENT to the cheapest tx with `weight = 100`) let mut t = TestExternalities::::new_with_code(COMPACT_CODE, Storage { top: map![ - >::hashed_key_for(alice()) => { - (100 * DOLLARS).encode() + >::hashed_key_for(alice()) => { + (100 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS).encode() }, - >::hashed_key_for(bob()) => { - (10 * DOLLARS).encode() + >::hashed_key_for(bob()) => { + (10 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS).encode() }, >::hashed_key().to_vec() => { - (110 * DOLLARS).encode() + (110 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS).encode() }, >::hashed_key().to_vec() => vec![0u8; 16], >::hashed_key_for(0) => vec![0u8; 32] @@ -193,9 +193,7 @@ fn transaction_fee_is_correct_ultimate() { // we know that weight to fee multiplier is effect-less in block 1. assert_eq!(weight_fee as Balance, MILLICENTS); balance_alice -= weight_fee; - balance_alice -= tip; - balance_alice -= TransferFee::get(); assert_eq!(Balances::total_balance(&alice()), balance_alice); }); diff --git a/bin/node/executor/tests/submit_transaction.rs b/bin/node/executor/tests/submit_transaction.rs index 9e91ffc76b38f..40c0c6b80fefd 100644 --- a/bin/node/executor/tests/submit_transaction.rs +++ b/bin/node/executor/tests/submit_transaction.rs @@ -167,7 +167,8 @@ fn submitted_transaction_should_be_valid() { // add balance to the account let author = extrinsic.signature.clone().unwrap().0; let address = Indices::lookup(author).unwrap(); - >::insert(&address, 5_000_000_000_000); + let account = pallet_balances::AccountData { free: 5_000_000_000_000, ..Default::default() }; + >::insert(&address, account); // check validity let res = Executive::validate_transaction(extrinsic); diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index e55ca3b189a8e..2eb2c8e43c827 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -688,6 +688,16 @@ impl, I: Instance> Module { } } + /// Get the free balance of an account. + pub fn free_balance(who: impl sp_std::borrow::Borrow) -> T::Balance { + Account::::get(who.borrow()).free + } + + /// Get the reserved balance of an account. + pub fn reserved_balance(who: impl sp_std::borrow::Borrow) -> T::Balance { + Account::::get(who.borrow()).reserved + } + /// Set both the free and reserved balance of an account to some new value. Will enforce /// `ExistentialDeposit` law, annulling the account as needed. /// @@ -1080,13 +1090,13 @@ impl, I: Instance> Currency for Module where Self::set_account(transactor, &from_account, &old_from_account); - // Emit transfer event. - Self::deposit_event(RawEvent::Transfer(transactor.clone(), dest.clone(), value, fee)); - // Take action on the set_account call. // This will emit events that _resulted_ from the transfer. Self::set_account(dest, &to_account, &old_to_account); + // Emit transfer event. + Self::deposit_event(RawEvent::Transfer(transactor.clone(), dest.clone(), value, fee)); + T::TransferPayment::on_unbalanced(NegativeImbalance::new(fee)); Ok(()) @@ -1242,8 +1252,7 @@ impl, I: Instance> Currency for Module where } } -impl, I: Instance> ReservableCurrency for Module -where +impl, I: Instance> ReservableCurrency for Module where T::Balance: MaybeSerializeDeserialize + Debug { /// Check if `who` can reserve `value` from their free balance. diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 20f18b86163a9..2c6e20c9b2c7f 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -1389,14 +1389,14 @@ type OnReapAccount = System; ); assert_ok!(Democracy::vote(Origin::signed(1), r, AYE)); - assert_eq!(Balances::reserved_balance(6), 12); + assert_eq!(Balances::reserved_balance(&6), 12); next_block(); next_block(); - assert_eq!(Balances::reserved_balance(6), 0); - assert_eq!(Balances::free_balance(6), 60); - assert_eq!(Balances::free_balance(42), 2); + assert_eq!(Balances::reserved_balance(&6), 0); + assert_eq!(Balances::free_balance(&6), 60); + assert_eq!(Balances::free_balance(&42), 2); }); } @@ -1407,7 +1407,7 @@ type OnReapAccount = System; PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1); assert_ok!(Democracy::note_preimage(Origin::signed(6), set_balance_proposal(2))); - assert_eq!(Balances::reserved_balance(6), 12); + assert_eq!(Balances::reserved_balance(&6), 12); next_block(); assert_noop!( @@ -1417,8 +1417,8 @@ type OnReapAccount = System; next_block(); assert_ok!(Democracy::reap_preimage(Origin::signed(6), set_balance_proposal_hash(2))); - assert_eq!(Balances::reserved_balance(6), 0); - assert_eq!(Balances::free_balance(6), 60); + assert_eq!(Balances::reserved_balance(&6), 0); + assert_eq!(Balances::free_balance(&6), 60); }); } @@ -1433,7 +1433,7 @@ type OnReapAccount = System; PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1); assert_ok!(Democracy::note_preimage(Origin::signed(6), set_balance_proposal(2))); - assert_eq!(Balances::reserved_balance(6), 12); + assert_eq!(Balances::reserved_balance(&6), 12); next_block(); next_block(); @@ -1445,9 +1445,9 @@ type OnReapAccount = System; next_block(); assert_ok!(Democracy::reap_preimage(Origin::signed(5), set_balance_proposal_hash(2))); - assert_eq!(Balances::reserved_balance(6), 0); - assert_eq!(Balances::free_balance(6), 48); - assert_eq!(Balances::free_balance(5), 62); + assert_eq!(Balances::reserved_balance(&6), 0); + assert_eq!(Balances::free_balance(&6), 48); + assert_eq!(Balances::free_balance(&5), 62); }); } @@ -1477,7 +1477,7 @@ type OnReapAccount = System; next_block(); - assert_eq!(Balances::free_balance(42), 2); + assert_eq!(Balances::free_balance(&42), 2); }); } @@ -2411,22 +2411,19 @@ type OnReapAccount = System; assert_eq!(Balances::locks(2), vec![BalanceLock { id: DEMOCRACY_ID, amount: u64::max_value(), - until: u64::max_value(), - reasons: WithdrawReason::Transfer.into() + reasons: pallet_balances::Reasons::Misc, }]); assert_eq!(Democracy::locks(2), Some(18)); assert_eq!(Balances::locks(3), vec![BalanceLock { id: DEMOCRACY_ID, amount: u64::max_value(), - until: u64::max_value(), - reasons: WithdrawReason::Transfer.into() + reasons: pallet_balances::Reasons::Misc, }]); assert_eq!(Democracy::locks(3), Some(10)); assert_eq!(Balances::locks(4), vec![BalanceLock { id: DEMOCRACY_ID, amount: u64::max_value(), - until: u64::max_value(), - reasons: WithdrawReason::Transfer.into() + reasons: pallet_balances::Reasons::Misc, }]); assert_eq!(Democracy::locks(4), Some(6)); assert_eq!(Balances::locks(5), vec![]); diff --git a/frame/elections/src/mock.rs b/frame/elections/src/mock.rs index 9a4789a51d277..3274dd57b4afa 100644 --- a/frame/elections/src/mock.rs +++ b/frame/elections/src/mock.rs @@ -266,7 +266,8 @@ pub(crate) fn create_candidate(i: u64, index: u32) { } pub(crate) fn balances(who: &u64) -> (u64, u64) { - (Balances::free_balance(who), Balances::reserved_balance(who)) + let a = Balances::account(who); + (a.free, a.reserved) } pub(crate) fn locks(who: &u64) -> Vec { diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index c7ab708ade903..cf4aafd9753db 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -560,7 +560,7 @@ type OnReapAccount = System; header: Header { parent_hash: [69u8; 32].into(), number: 1, - state_root: hex!("c6b01b27df520ba23adb96e7fc032acb7c586ba1b477c6282de43184111f2091").into(), + state_root: hex!("a0b84fec49718caf59350dab6ec2993f12db399a7cccdb80f3cf79618ed93bd8").into(), extrinsics_root: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").into(), digest: Digest { logs: vec![], }, }, diff --git a/frame/society/src/tests.rs b/frame/society/src/tests.rs index 3e5afc47f500a..2d566e0f0e785 100644 --- a/frame/society/src/tests.rs +++ b/frame/society/src/tests.rs @@ -82,11 +82,11 @@ fn unfounding_works() { #[test] fn basic_new_member_works() { EnvBuilder::new().execute(|| { - assert_eq!(Balances::free_balance(20), 50); + assert_eq!(Balances::free_balance(&20), 50); // Bid causes Candidate Deposit to be reserved. assert_ok!(Society::bid(Origin::signed(20), 0)); - assert_eq!(Balances::free_balance(20), 25); - assert_eq!(Balances::reserved_balance(20), 25); + assert_eq!(Balances::free_balance(&20), 25); + assert_eq!(Balances::reserved_balance(&20), 25); // Rotate period every 4 blocks run_to_block(4); // 20 is now a candidate @@ -98,8 +98,8 @@ fn basic_new_member_works() { // 20 is now a member of the society assert_eq!(Society::members(), vec![10, 20]); // Reserved balance is returned - assert_eq!(Balances::free_balance(20), 50); - assert_eq!(Balances::reserved_balance(20), 0); + assert_eq!(Balances::free_balance(&20), 50); + assert_eq!(Balances::reserved_balance(&20), 0); }); } @@ -115,7 +115,7 @@ fn bidding_works() { run_to_block(4); // Pot is 1000 after "PeriodSpend" assert_eq!(Society::pot(), 1000); - assert_eq!(Balances::free_balance(Society::account_id()), 10_000); + assert_eq!(Balances::free_balance(&Society::account_id()), 10_000); // Choose smallest bidding users whose total is less than pot assert_eq!(Society::candidates(), vec![ create_bid(300, 30, BidKind::Deposit(25)), @@ -128,7 +128,7 @@ fn bidding_works() { // Candidates become members after a period rotation assert_eq!(Society::members(), vec![10, 30, 40]); // Pot is increased by 1000, but pays out 700 to the members - assert_eq!(Balances::free_balance(Society::account_id()), 9_300); + assert_eq!(Balances::free_balance(&Society::account_id()), 9_300); assert_eq!(Society::pot(), 1_300); // Left over from the original bids is 50 who satisfies the condition of bid less than pot. assert_eq!(Society::candidates(), vec![ create_bid(500, 50, BidKind::Deposit(25)) ]); @@ -139,7 +139,7 @@ fn bidding_works() { assert_eq!(Society::members(), vec![10, 30, 40, 50]); // Pot is increased by 1000, and 500 is paid out. Total payout so far is 1200. assert_eq!(Society::pot(), 1_800); - assert_eq!(Balances::free_balance(Society::account_id()), 8_800); + assert_eq!(Balances::free_balance(&Society::account_id()), 8_800); // No more candidates satisfy the requirements assert_eq!(Society::candidates(), vec![]); assert_ok!(Society::defender_vote(Origin::signed(10), true)); // Keep defender around @@ -150,7 +150,7 @@ fn bidding_works() { // Pot is increased by 1000 again assert_eq!(Society::pot(), 2_800); // No payouts - assert_eq!(Balances::free_balance(Society::account_id()), 8_800); + assert_eq!(Balances::free_balance(&Society::account_id()), 8_800); // Candidate 60 now qualifies based on the increased pot size. assert_eq!(Society::candidates(), vec![ create_bid(1900, 60, BidKind::Deposit(25)) ]); // Candidate 60 is voted in. @@ -160,7 +160,7 @@ fn bidding_works() { assert_eq!(Society::members(), vec![10, 30, 40, 50, 60]); // Pay them assert_eq!(Society::pot(), 1_900); - assert_eq!(Balances::free_balance(Society::account_id()), 6_900); + assert_eq!(Balances::free_balance(&Society::account_id()), 6_900); }); } @@ -171,15 +171,15 @@ fn unbidding_works() { assert_ok!(Society::bid(Origin::signed(20), 1000)); assert_ok!(Society::bid(Origin::signed(30), 0)); // Balances are reserved - assert_eq!(Balances::free_balance(30), 25); - assert_eq!(Balances::reserved_balance(30), 25); + assert_eq!(Balances::free_balance(&30), 25); + assert_eq!(Balances::reserved_balance(&30), 25); // Must know right position to unbid + cannot unbid someone else assert_noop!(Society::unbid(Origin::signed(30), 1), Error::::BadPosition); // Can unbid themselves with the right position assert_ok!(Society::unbid(Origin::signed(30), 0)); // Balance is returned - assert_eq!(Balances::free_balance(30), 50); - assert_eq!(Balances::reserved_balance(30), 0); + assert_eq!(Balances::free_balance(&30), 50); + assert_eq!(Balances::reserved_balance(&30), 0); // 20 wins candidacy run_to_block(4); assert_eq!(Society::candidates(), vec![ create_bid(1000, 20, BidKind::Deposit(25)) ]); @@ -190,7 +190,7 @@ fn unbidding_works() { fn payout_works() { EnvBuilder::new().execute(|| { // Original balance of 50 - assert_eq!(Balances::free_balance(20), 50); + assert_eq!(Balances::free_balance(&20), 50); assert_ok!(Society::bid(Origin::signed(20), 1000)); run_to_block(4); assert_ok!(Society::vote(Origin::signed(10), 20, true)); @@ -200,7 +200,7 @@ fn payout_works() { run_to_block(9); // payout should be here assert_ok!(Society::payout(Origin::signed(20))); - assert_eq!(Balances::free_balance(20), 1050); + assert_eq!(Balances::free_balance(&20), 1050); }); } @@ -221,11 +221,11 @@ fn basic_new_member_skeptic_works() { fn basic_new_member_reject_works() { EnvBuilder::new().execute(|| { // Starting Balance - assert_eq!(Balances::free_balance(20), 50); + assert_eq!(Balances::free_balance(&20), 50); // 20 makes a bid assert_ok!(Society::bid(Origin::signed(20), 0)); - assert_eq!(Balances::free_balance(20), 25); - assert_eq!(Balances::reserved_balance(20), 25); + assert_eq!(Balances::free_balance(&20), 25); + assert_eq!(Balances::reserved_balance(&20), 25); // Rotation Period run_to_block(4); assert_eq!(Society::candidates(), vec![create_bid(0, 20, BidKind::Deposit(25))]); @@ -243,7 +243,7 @@ fn basic_new_member_reject_works() { #[test] fn slash_payout_works() { EnvBuilder::new().execute(|| { - assert_eq!(Balances::free_balance(20), 50); + assert_eq!(Balances::free_balance(&20), 50); assert_ok!(Society::bid(Origin::signed(20), 1000)); run_to_block(4); assert_ok!(Society::vote(Origin::signed(10), 20, true)); @@ -257,14 +257,14 @@ fn slash_payout_works() { run_to_block(9); // payout should be here, but 500 less assert_ok!(Society::payout(Origin::signed(20))); - assert_eq!(Balances::free_balance(20), 550); + assert_eq!(Balances::free_balance(&20), 550); }); } #[test] fn slash_payout_multi_works() { EnvBuilder::new().execute(|| { - assert_eq!(Balances::free_balance(20), 50); + assert_eq!(Balances::free_balance(&20), 50); // create a few payouts Society::bump_payout(&20, 5, 100); Society::bump_payout(&20, 10, 100); @@ -330,12 +330,12 @@ fn suspended_member_lifecycle_works() { fn suspended_candidate_rejected_works() { EnvBuilder::new().execute(|| { // Starting Balance - assert_eq!(Balances::free_balance(20), 50); - assert_eq!(Balances::free_balance(Society::account_id()), 10000); + assert_eq!(Balances::free_balance(&20), 50); + assert_eq!(Balances::free_balance(&Society::account_id()), 10000); // 20 makes a bid assert_ok!(Society::bid(Origin::signed(20), 0)); - assert_eq!(Balances::free_balance(20), 25); - assert_eq!(Balances::reserved_balance(20), 25); + assert_eq!(Balances::free_balance(&20), 25); + assert_eq!(Balances::reserved_balance(&20), 25); // Rotation Period run_to_block(4); assert_eq!(Society::candidates(), vec![create_bid(0, 20, BidKind::Deposit(25))]); @@ -369,10 +369,10 @@ fn suspended_candidate_rejected_works() { // Suspension judgement origin rejects the candidate assert_ok!(Society::judge_suspended_candidate(Origin::signed(2), 20, Judgement::Reject)); // User is slashed - assert_eq!(Balances::free_balance(20), 25); - assert_eq!(Balances::reserved_balance(20), 0); + assert_eq!(Balances::free_balance(&20), 25); + assert_eq!(Balances::reserved_balance(&20), 0); // Funds are deposited to society account - assert_eq!(Balances::free_balance(Society::account_id()), 10025); + assert_eq!(Balances::free_balance(&Society::account_id()), 10025); // Cleaned up assert_eq!(Society::candidates(), vec![]); assert_eq!(>::get(20), None); @@ -837,7 +837,7 @@ fn zero_bid_works() { run_to_block(4); // Pot is 1000 after "PeriodSpend" assert_eq!(Society::pot(), 1000); - assert_eq!(Balances::free_balance(Society::account_id()), 10_000); + assert_eq!(Balances::free_balance(&Society::account_id()), 10_000); // Choose smallest bidding users whose total is less than pot, with only one zero bid. assert_eq!(Society::candidates(), vec![ create_bid(0, 30, BidKind::Deposit(25)), diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 3d7dcc767897d..0051c9a0bfe15 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -178,9 +178,7 @@ impl ChargeTransactionPayment { let adjusted_fee = targeted_fee_adjustment.saturated_multiply_accumulate(adjustable_fee); let base_fee = T::TransactionBaseFee::get(); - let final_fee = base_fee.saturating_add(adjusted_fee).saturating_add(tip); - - final_fee + base_fee.saturating_add(adjusted_fee).saturating_add(tip) } else { tip } From 4774820cf3d09920e96c272ed49c35c6a8a52380 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 24 Jan 2020 17:21:51 +0100 Subject: [PATCH 21/29] Fix repatriate reserve --- frame/balances/src/lib.rs | 4 ++++ frame/democracy/src/lib.rs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 2eb2c8e43c827..89d7510227576 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -1340,6 +1340,10 @@ impl, I: Instance> ReservableCurrency for Module ) -> result::Result { if value.is_zero() { return Ok (Zero::zero()) } + if slashed == beneficiary { + return Ok(Self::unreserve(slashed, value)); + } + let old_to_account = Self::account(beneficiary); let mut to_account = old_to_account.clone(); ensure!(!to_account.total().is_zero(), Error::::DeadAccount); diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 2c6e20c9b2c7f..9a08d563ce8a8 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -1417,8 +1417,8 @@ type OnReapAccount = System; next_block(); assert_ok!(Democracy::reap_preimage(Origin::signed(6), set_balance_proposal_hash(2))); - assert_eq!(Balances::reserved_balance(&6), 0); assert_eq!(Balances::free_balance(&6), 60); + assert_eq!(Balances::reserved_balance(&6), 0); }); } From 3d8b2c17b578d98ca55360cb67f8ef72652f1fa0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 26 Jan 2020 16:20:12 +0100 Subject: [PATCH 22/29] Fixes --- frame/balances/src/lib.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 89d7510227576..15b7480ae75e6 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -151,16 +151,19 @@ use sp_std::prelude::*; use sp_std::{cmp, result, mem, fmt::Debug, ops::BitOr}; use codec::{Codec, Encode, Decode}; -use frame_support::{StorageValue, Parameter, decl_event, decl_storage, decl_module, decl_error, ensure, traits::{ - UpdateBalanceOutcome, Currency, OnReapAccount, OnUnbalanced, TryDrop, - WithdrawReason, WithdrawReasons, LockIdentifier, LockableCurrency, ExistenceRequirement, - Imbalance, SignedImbalance, ReservableCurrency, Get, -}, weights::SimpleDispatchInfo, Twox128}; +use frame_support::{ + StorageValue, Parameter, decl_event, decl_storage, decl_module, decl_error, ensure, + weights::SimpleDispatchInfo, Twox128, traits::{ + UpdateBalanceOutcome, Currency, OnReapAccount, OnUnbalanced, TryDrop, + WithdrawReason, WithdrawReasons, LockIdentifier, LockableCurrency, ExistenceRequirement, + Imbalance, SignedImbalance, ReservableCurrency, Get, ExistenceRequirement::KeepAlive + } +}; use sp_runtime::{ RuntimeDebug, DispatchResult, DispatchError, traits::{ - Zero, SimpleArithmetic, StaticLookup, Member, CheckedAdd, CheckedSub, MaybeSerializeDeserialize, - Saturating, Bounded, + Zero, SimpleArithmetic, StaticLookup, Member, CheckedAdd, CheckedSub, + MaybeSerializeDeserialize, Saturating, Bounded, }, }; use frame_system::{self as system, IsDeadAccount, OnNewAccount, ensure_signed, ensure_root}; @@ -521,7 +524,7 @@ decl_module! { ) { let transactor = ensure_signed(origin)?; let dest = T::Lookup::lookup(dest)?; - >::transfer(&transactor, &dest, value, ExistenceRequirement::KeepAlive)?; + >::transfer(&transactor, &dest, value, KeepAlive)?; } fn on_initialize() { @@ -628,7 +631,6 @@ impl, I: Instance> Module { // Upgrade from the pre-#4649 balances/vesting into the new balances. pub fn do_upgrade() { - // TODO: Handle Instance parameter in storage access. // First, migrate from old FreeBalance to new Account. // We also move all locks across since only accounts with FreeBalance values have locks. // FreeBalance: map T::AccountId => T::Balance From 2735132a412f2b3eb2da1cc4a2e11221fe88017b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 26 Jan 2020 19:35:13 +0100 Subject: [PATCH 23/29] Add test for migration --- Cargo.lock | 2 ++ frame/balances/src/lib.rs | 2 +- frame/democracy/Cargo.toml | 2 ++ frame/democracy/src/lib.rs | 53 +++++++++++++++++++++++++++++++++++--- 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ec22258303cb..af45b236b1345 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3652,6 +3652,7 @@ version = "2.0.0" dependencies = [ "frame-support 2.0.0", "frame-system 2.0.0", + "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "pallet-balances 2.0.0", "parity-scale-codec 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3659,6 +3660,7 @@ dependencies = [ "sp-io 2.0.0", "sp-runtime 2.0.0", "sp-std 2.0.0", + "sp-storage 2.0.0", ] [[package]] diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 15b7480ae75e6..2e62e309593dc 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -597,7 +597,7 @@ fn put_storage_value(module: &[u8], item: &[u8], hash: &[u8], value: key[0..16].copy_from_slice(&Twox128::hash(module)); key[16..32].copy_from_slice(&Twox128::hash(item)); key[32..].copy_from_slice(hash); - value.using_encoded(|value| frame_support::storage::unhashed::put(&key, value)); + frame_support::storage::unhashed::put(&key, &value); } fn kill_storage_value(module: &[u8], item: &[u8], hash: &[u8]) { diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index 02145e8589bab..af79e973263b3 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -16,6 +16,8 @@ frame-system = { version = "2.0.0", default-features = false, path = "../system" [dev-dependencies] sp-core = { version = "2.0.0", path = "../../primitives/core" } pallet-balances = { version = "2.0.0", path = "../balances" } +sp-storage = { path = "../../primitives/storage" } +hex-literal = "0.2.1" [features] default = ["std"] diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 9a08d563ce8a8..48e61dac9a617 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -1167,15 +1167,16 @@ mod tests { use std::cell::RefCell; use frame_support::{ impl_outer_origin, impl_outer_dispatch, assert_noop, assert_ok, parameter_types, - ord_parameter_types, traits::Contains, weights::Weight, + ord_parameter_types, traits::{Contains, ExistenceRequirement::AllowDeath}, weights::Weight, }; use sp_core::H256; use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup, Bounded, BadOrigin}, + traits::{BlakeTwo256, IdentityLookup, Bounded, BadOrigin, OnInitialize}, testing::Header, Perbill, }; use pallet_balances::{BalanceLock, Error as BalancesError}; use frame_system::EnsureSignedBy; + use sp_storage::Storage; const AYE: Vote = Vote{ aye: true, conviction: Conviction::None }; const NAY: Vote = Vote{ aye: false, conviction: Conviction::None }; @@ -1226,7 +1227,7 @@ mod tests { } impl pallet_balances::Trait for Test { type Balance = u64; -type OnReapAccount = System; + type OnReapAccount = System; type OnNewAccount = (); type Event = (); type TransferPayment = (); @@ -1295,6 +1296,52 @@ type OnReapAccount = System; type Balances = pallet_balances::Module; type Democracy = Module; + #[test] + fn refresh_from_data() { + let mut s = Storage::default(); + use hex_literal::*; + let data = vec![ + (hex!["26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac"].to_vec(), hex!["0100000000000000"].to_vec()), + (hex!["26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850"].to_vec(), hex!["02000000"].to_vec()), + (hex!["26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7"].to_vec(), hex!["08000000000000000000000000"].to_vec()), + (hex!["26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc"].to_vec(), hex!["4545454545454545454545454545454545454545454545454545454545454545"].to_vec()), + (hex!["26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c11874681e47a19e6b29b0a65b9591762ce5143ed30d0261e5d24a3201752506b20f15c"].to_vec(), hex!["4545454545454545454545454545454545454545454545454545454545454545"].to_vec()), + (hex!["3a636f6465"].to_vec(), hex![""].to_vec()), + (hex!["3a65787472696e7369635f696e646578"].to_vec(), hex!["00000000"].to_vec()), + (hex!["3a686561707061676573"].to_vec(), hex!["0800000000000000"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc61dbd7d0b561a41d23c2a469ad42fbd70d5438bae826f6fd607413190c37c363b"].to_vec(), hex!["046d697363202020200300000000000000ffffffffffffffff04"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc66cddb367afbd583bb48f9bbd7d5ba3b1d0738b4881b1cddd38169526d8158137"].to_vec(), hex!["0474786665657320200300000000000000ffffffffffffffff01"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc6e88b43fded6323ef02ffeffbd8c40846ee09bf316271bd22369659c959dd733a"].to_vec(), hex!["08616c6c20202020200300000000000000ffffffffffffffff1f64656d6f63726163ffffffffffffffff030000000000000002"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f3c22813def93ef32c365b55cb92f10f91dbd7d0b561a41d23c2a469ad42fbd70d5438bae826f6fd607413190c37c363b"].to_vec(), hex!["0500000000000000"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80"].to_vec(), hex!["d200000000000000"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b41dbd7d0b561a41d23c2a469ad42fbd70d5438bae826f6fd607413190c37c363b"].to_vec(), hex!["0500000000000000"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b46cddb367afbd583bb48f9bbd7d5ba3b1d0738b4881b1cddd38169526d8158137"].to_vec(), hex!["1e00000000000000"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b4b8788bb218b185b63e3e92653953f29b6b143fb8cf5159fc908632e6fe490501"].to_vec(), hex!["3c00000000000000"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b4e88b43fded6323ef02ffeffbd8c40846ee09bf316271bd22369659c959dd733a"].to_vec(), hex!["1400000000000000"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b4e96760d274653a39b429a87ebaae9d3aa4fdf58b9096cf0bebc7c4e5a4c2ed8d"].to_vec(), hex!["2800000000000000"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b4effb728943197fd12e694cbf3f3ede28fbf7498b0370c6dfa0013874b417c178"].to_vec(), hex!["3200000000000000"].to_vec()), + (hex!["f2794c22e353e9a839f12faab03a911b7f17cdfbfa73331856cca0acddd7842e"].to_vec(), hex!["00000000"].to_vec()), + (hex!["f2794c22e353e9a839f12faab03a911bbdcb0c5143a8617ed38ae3810dd45bc6"].to_vec(), hex!["00000000"].to_vec()), + (hex!["f2794c22e353e9a839f12faab03a911be2f6cb0456905c189bcb0458f9440f13"].to_vec(), hex!["00000000"].to_vec()), + ]; + s.top = data.into_iter().collect(); + sp_io::TestExternalities::new(s).execute_with(|| { + Balances::on_initialize(1); + assert_eq!(Balances::free_balance(&1), 5); + assert_eq!(Balances::reserved_balance(&1), 5); + assert_eq!(Balances::free_balance(&2), 20); + assert_eq!(Balances::reserved_balance(&2), 0); + // only 7 available for xfer + assert!(>::transfer(&1, &2, 8, AllowDeath).is_err()); + // all 20 locked until #5. + assert!(>::transfer(&2, &1, 1, AllowDeath).is_err()); + assert_ok!(>::transfer(&1, &2, 2, AllowDeath)); + fast_forward_to(5); + assert_ok!(Democracy::unlock(Origin::signed(2), 2)); + assert_ok!(>::transfer(&2, &1, 17, AllowDeath)); + }); + } + #[test] fn params_should_work() { new_test_ext().execute_with(|| { From 746b630a52029938d400347221da5820056c1340 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 26 Jan 2020 22:00:25 +0100 Subject: [PATCH 24/29] Final cleanups --- Cargo.lock | 18 ++++++ Cargo.toml | 1 + frame/balances/src/lib.rs | 100 +++++++------------------------- frame/balances/src/migration.rs | 83 ++++++++++++++++++++++++++ frame/democracy/Cargo.toml | 2 +- frame/democracy/src/lib.rs | 21 ++++--- frame/vesting/Cargo.toml | 2 + frame/vesting/src/lib.rs | 56 +++++++++++++++++- 8 files changed, 191 insertions(+), 92 deletions(-) create mode 100644 frame/balances/src/migration.rs diff --git a/Cargo.lock b/Cargo.lock index af45b236b1345..d027cd0a18c78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4096,6 +4096,24 @@ dependencies = [ "sp-std 2.0.0", ] +[[package]] +name = "pallet-vesting" +version = "2.0.0" +dependencies = [ + "enumflags2 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "frame-support 2.0.0", + "frame-system 2.0.0", + "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pallet-balances 2.0.0", + "parity-scale-codec 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-core 2.0.0", + "sp-io 2.0.0", + "sp-runtime 2.0.0", + "sp-std 2.0.0", + "sp-storage 2.0.0", +] + [[package]] name = "parity-bytes" version = "0.1.1" diff --git a/Cargo.toml b/Cargo.toml index fb15de2ebed12..361f7348b309f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,6 +98,7 @@ members = [ "frame/transaction-payment/rpc/runtime-api", "frame/treasury", "frame/utility", + "frame/vesting", "primitives/allocator", "primitives/application-crypto", "primitives/application-crypto/test", diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 2e62e309593dc..d981c2131b86b 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -148,12 +148,18 @@ #![cfg_attr(not(feature = "std"), no_std)] +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; +mod migration; + use sp_std::prelude::*; use sp_std::{cmp, result, mem, fmt::Debug, ops::BitOr}; use codec::{Codec, Encode, Decode}; use frame_support::{ StorageValue, Parameter, decl_event, decl_storage, decl_module, decl_error, ensure, - weights::SimpleDispatchInfo, Twox128, traits::{ + weights::SimpleDispatchInfo, traits::{ UpdateBalanceOutcome, Currency, OnReapAccount, OnUnbalanced, TryDrop, WithdrawReason, WithdrawReasons, LockIdentifier, LockableCurrency, ExistenceRequirement, Imbalance, SignedImbalance, ReservableCurrency, Get, ExistenceRequirement::KeepAlive @@ -167,11 +173,7 @@ use sp_runtime::{ }, }; use frame_system::{self as system, IsDeadAccount, OnNewAccount, ensure_signed, ensure_root}; - -#[cfg(test)] -mod mock; -#[cfg(test)] -mod tests; +use migration::{get_storage_value, put_storage_value, StorageIterator}; pub use self::imbalances::{PositiveImbalance, NegativeImbalance}; @@ -344,7 +346,7 @@ pub struct AccountData { impl AccountData { /// How much this account's balance can be reduced for the given `reasons`. - pub fn usable(&self, reasons: Reasons) -> Balance { + fn usable(&self, reasons: Reasons) -> Balance { self.free.saturating_sub(self.frozen(reasons)) } /// The amount that this account's free balance may not be reduced beyond for the given @@ -536,78 +538,6 @@ decl_module! { } } -pub struct StorageIterator { - prefix: [u8; 32], - previous_key: Vec, - drain: bool, - _phantom: ::sp_std::marker::PhantomData, -} - -use frame_support::StorageHasher; - -impl StorageIterator { - fn new(module: &[u8], item: &[u8]) -> Self { - let mut prefix = [0u8; 32]; - prefix[0..16].copy_from_slice(&Twox128::hash(module)); - prefix[16..32].copy_from_slice(&Twox128::hash(item)); - Self { prefix, previous_key: prefix[..].to_vec(), drain: false, _phantom: Default::default() } - } - fn drain(mut self) -> Self { - self.drain = true; - self - } -} - -impl Iterator for StorageIterator { - type Item = (Vec, T); - fn next(&mut self) -> Option<(Vec, T)> { - loop { - let maybe_next = sp_io::storage::next_key(&self.previous_key) - .filter(|n| n.starts_with(&self.prefix)); - break match maybe_next { - Some(next) => { - self.previous_key = next.clone(); - let maybe_value = frame_support::storage::unhashed::get::(&next); - match maybe_value { - Some(value) => { - if self.drain { - frame_support::storage::unhashed::kill(&next); - } - Some((self.previous_key[32..].to_vec(), value)) - } - None => continue, - } - } - None => None, - } - } - } -} - -fn get_storage_value(module: &[u8], item: &[u8], hash: &[u8]) -> Option { - let mut key = vec![0u8; 32 + hash.len()]; - key[0..16].copy_from_slice(&Twox128::hash(module)); - key[16..32].copy_from_slice(&Twox128::hash(item)); - key[32..].copy_from_slice(hash); - frame_support::storage::unhashed::get::(&key) -} - -fn put_storage_value(module: &[u8], item: &[u8], hash: &[u8], value: T) { - let mut key = vec![0u8; 32 + hash.len()]; - key[0..16].copy_from_slice(&Twox128::hash(module)); - key[16..32].copy_from_slice(&Twox128::hash(item)); - key[32..].copy_from_slice(hash); - frame_support::storage::unhashed::put(&key, &value); -} - -fn kill_storage_value(module: &[u8], item: &[u8], hash: &[u8]) { - let mut key = vec![0u8; 32 + hash.len()]; - key[0..16].copy_from_slice(&Twox128::hash(module)); - key[16..32].copy_from_slice(&Twox128::hash(item)); - key[32..].copy_from_slice(hash); - frame_support::storage::unhashed::kill(&key); -} - #[derive(Decode)] struct OldBalanceLock { id: LockIdentifier, @@ -695,6 +625,18 @@ impl, I: Instance> Module { Account::::get(who.borrow()).free } + /// Get the balance of an account that can be used for transfers, reservations, or any other + /// non-locking, non-transaction-fee activity. Will be at most `free_balance`. + pub fn usable_balance(who: impl sp_std::borrow::Borrow) -> T::Balance { + Account::::get(who.borrow()).usable(Reasons::Misc) + } + + /// Get the balance of an account that can be used for paying transaction fees (not tipping, + /// or any other kind of fees, though). Will be at most `free_balance`. + pub fn usable_balance_for_fees(who: impl sp_std::borrow::Borrow) -> T::Balance { + Account::::get(who.borrow()).usable(Reasons::Fee) + } + /// Get the reserved balance of an account. pub fn reserved_balance(who: impl sp_std::borrow::Borrow) -> T::Balance { Account::::get(who.borrow()).reserved diff --git a/frame/balances/src/migration.rs b/frame/balances/src/migration.rs new file mode 100644 index 0000000000000..5be076d2b00eb --- /dev/null +++ b/frame/balances/src/migration.rs @@ -0,0 +1,83 @@ +// Copyright 2017-2020 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Some utilities for helping access storage with arbitrary key types. + +use codec::{Encode, Decode}; +use frame_support::{StorageHasher, Twox128}; + +pub struct StorageIterator { + prefix: [u8; 32], + previous_key: Vec, + drain: bool, + _phantom: ::sp_std::marker::PhantomData, +} + +impl StorageIterator { + pub fn new(module: &[u8], item: &[u8]) -> Self { + let mut prefix = [0u8; 32]; + prefix[0..16].copy_from_slice(&Twox128::hash(module)); + prefix[16..32].copy_from_slice(&Twox128::hash(item)); + Self { prefix, previous_key: prefix[..].to_vec(), drain: false, _phantom: Default::default() } + } + pub fn drain(mut self) -> Self { + self.drain = true; + self + } +} + +impl Iterator for StorageIterator { + type Item = (Vec, T); + + fn next(&mut self) -> Option<(Vec, T)> { + loop { + let maybe_next = sp_io::storage::next_key(&self.previous_key) + .filter(|n| n.starts_with(&self.prefix)); + break match maybe_next { + Some(next) => { + self.previous_key = next.clone(); + let maybe_value = frame_support::storage::unhashed::get::(&next); + match maybe_value { + Some(value) => { + if self.drain { + frame_support::storage::unhashed::kill(&next); + } + Some((self.previous_key[32..].to_vec(), value)) + } + None => continue, + } + } + None => None, + } + } + } +} + +pub fn get_storage_value(module: &[u8], item: &[u8], hash: &[u8]) -> Option { + let mut key = vec![0u8; 32 + hash.len()]; + key[0..16].copy_from_slice(&Twox128::hash(module)); + key[16..32].copy_from_slice(&Twox128::hash(item)); + key[32..].copy_from_slice(hash); + frame_support::storage::unhashed::get::(&key) +} + +pub fn put_storage_value(module: &[u8], item: &[u8], hash: &[u8], value: T) { + let mut key = vec![0u8; 32 + hash.len()]; + key[0..16].copy_from_slice(&Twox128::hash(module)); + key[16..32].copy_from_slice(&Twox128::hash(item)); + key[32..].copy_from_slice(hash); + frame_support::storage::unhashed::put(&key, &value); +} diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index af79e973263b3..b32c57ea80a4b 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -16,7 +16,7 @@ frame-system = { version = "2.0.0", default-features = false, path = "../system" [dev-dependencies] sp-core = { version = "2.0.0", path = "../../primitives/core" } pallet-balances = { version = "2.0.0", path = "../balances" } -sp-storage = { path = "../../primitives/storage" } +sp-storage = { version = "2.0.0", path = "../../primitives/storage" } hex-literal = "0.2.1" [features] diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 48e61dac9a617..c7f80f0c3d56b 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -1167,7 +1167,7 @@ mod tests { use std::cell::RefCell; use frame_support::{ impl_outer_origin, impl_outer_dispatch, assert_noop, assert_ok, parameter_types, - ord_parameter_types, traits::{Contains, ExistenceRequirement::AllowDeath}, weights::Weight, + ord_parameter_types, traits::Contains, weights::Weight, }; use sp_core::H256; use sp_runtime::{ @@ -1297,9 +1297,12 @@ mod tests { type Democracy = Module; #[test] - fn refresh_from_data() { + fn lock_info_via_migration_should_work() { let mut s = Storage::default(); - use hex_literal::*; + use hex_literal::hex; + // A dump of data from the previous version for which we know account 1 has 5 of its 10 + // reserved and 3 of the rest is locked for misc. Account 2 has all 20 locked until block 5 + // for everything and additionally 3 locked for just fees. let data = vec![ (hex!["26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac"].to_vec(), hex!["0100000000000000"].to_vec()), (hex!["26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850"].to_vec(), hex!["02000000"].to_vec()), @@ -1314,6 +1317,7 @@ mod tests { (hex!["c2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc6e88b43fded6323ef02ffeffbd8c40846ee09bf316271bd22369659c959dd733a"].to_vec(), hex!["08616c6c20202020200300000000000000ffffffffffffffff1f64656d6f63726163ffffffffffffffff030000000000000002"].to_vec()), (hex!["c2261276cc9d1f8598ea4b6a74b15c2f3c22813def93ef32c365b55cb92f10f91dbd7d0b561a41d23c2a469ad42fbd70d5438bae826f6fd607413190c37c363b"].to_vec(), hex!["0500000000000000"].to_vec()), (hex!["c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80"].to_vec(), hex!["d200000000000000"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f5f27b51b5ec208ee9cb25b55d8728243b8788bb218b185b63e3e92653953f29b6b143fb8cf5159fc908632e6fe490501"].to_vec(), hex!["1e0000000000000006000000000000000200000000000000"].to_vec()), (hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b41dbd7d0b561a41d23c2a469ad42fbd70d5438bae826f6fd607413190c37c363b"].to_vec(), hex!["0500000000000000"].to_vec()), (hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b46cddb367afbd583bb48f9bbd7d5ba3b1d0738b4881b1cddd38169526d8158137"].to_vec(), hex!["1e00000000000000"].to_vec()), (hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b4b8788bb218b185b63e3e92653953f29b6b143fb8cf5159fc908632e6fe490501"].to_vec(), hex!["3c00000000000000"].to_vec()), @@ -1329,16 +1333,15 @@ mod tests { Balances::on_initialize(1); assert_eq!(Balances::free_balance(&1), 5); assert_eq!(Balances::reserved_balance(&1), 5); + assert_eq!(Balances::usable_balance(&1), 2); + assert_eq!(Balances::usable_balance_for_fees(&1), 5); assert_eq!(Balances::free_balance(&2), 20); assert_eq!(Balances::reserved_balance(&2), 0); - // only 7 available for xfer - assert!(>::transfer(&1, &2, 8, AllowDeath).is_err()); - // all 20 locked until #5. - assert!(>::transfer(&2, &1, 1, AllowDeath).is_err()); - assert_ok!(>::transfer(&1, &2, 2, AllowDeath)); + assert_eq!(Balances::usable_balance(&2), 0); + assert_eq!(Balances::usable_balance_for_fees(&2), 17); fast_forward_to(5); assert_ok!(Democracy::unlock(Origin::signed(2), 2)); - assert_ok!(>::transfer(&2, &1, 17, AllowDeath)); + assert_eq!(Balances::usable_balance(&2), 17); }); } diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index cf87f55293d11..6923297af5616 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -17,6 +17,8 @@ frame-system = { version = "2.0.0", default-features = false, path = "../system" [dev-dependencies] sp-core = { version = "2.0.0", path = "../../primitives/core" } pallet-balances = { version = "2.0.0", path = "../balances" } +sp-storage = { version = "2.0.0", path = "../../primitives/storage" } +hex-literal = "0.2.1" [features] default = ["std"] diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 4da5c26a3e08f..10069c9905981 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -285,14 +285,16 @@ mod tests { use std::cell::RefCell; use frame_support::{ - assert_ok, assert_noop, impl_outer_origin, parameter_types, weights::Weight, traits::Get + assert_ok, assert_noop, impl_outer_origin, parameter_types, weights::Weight, + traits::Get }; use sp_core::H256; // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. use sp_runtime::{ - Perbill, testing::Header, traits::{BlakeTwo256, IdentityLookup, Identity}, + Perbill, testing::Header, traits::{BlakeTwo256, IdentityLookup, Identity, OnInitialize}, }; + use sp_storage::Storage; impl_outer_origin! { pub enum Origin for Test where system = frame_system {} @@ -332,7 +334,7 @@ mod tests { } impl pallet_balances::Trait for Test { type Balance = u64; -type OnReapAccount = System; + type OnReapAccount = System; type OnNewAccount = (); type Event = (); type TransferPayment = (); @@ -395,6 +397,54 @@ type OnReapAccount = System; } } + #[test] + fn vesting_info_via_migration_should_work() { + let mut s = Storage::default(); + use hex_literal::hex; + // A dump of data from the previous version for which we know account 6 vests 30 of its 60 + // over 5 blocks from block 3. + let data = vec![ + (hex!["26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac"].to_vec(), hex!["0100000000000000"].to_vec()), + (hex!["26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850"].to_vec(), hex!["02000000"].to_vec()), + (hex!["26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7"].to_vec(), hex!["08000000000000000000000000"].to_vec()), + (hex!["26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc"].to_vec(), hex!["4545454545454545454545454545454545454545454545454545454545454545"].to_vec()), + (hex!["26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c11874681e47a19e6b29b0a65b9591762ce5143ed30d0261e5d24a3201752506b20f15c"].to_vec(), hex!["4545454545454545454545454545454545454545454545454545454545454545"].to_vec()), + (hex!["3a636f6465"].to_vec(), hex![""].to_vec()), + (hex!["3a65787472696e7369635f696e646578"].to_vec(), hex!["00000000"].to_vec()), + (hex!["3a686561707061676573"].to_vec(), hex!["0800000000000000"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc61dbd7d0b561a41d23c2a469ad42fbd70d5438bae826f6fd607413190c37c363b"].to_vec(), hex!["046d697363202020200300000000000000ffffffffffffffff04"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc66cddb367afbd583bb48f9bbd7d5ba3b1d0738b4881b1cddd38169526d8158137"].to_vec(), hex!["0474786665657320200300000000000000ffffffffffffffff01"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc6e88b43fded6323ef02ffeffbd8c40846ee09bf316271bd22369659c959dd733a"].to_vec(), hex!["08616c6c20202020200300000000000000ffffffffffffffff1f64656d6f63726163ffffffffffffffff030000000000000002"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f3c22813def93ef32c365b55cb92f10f91dbd7d0b561a41d23c2a469ad42fbd70d5438bae826f6fd607413190c37c363b"].to_vec(), hex!["0500000000000000"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80"].to_vec(), hex!["d200000000000000"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f5f27b51b5ec208ee9cb25b55d8728243b8788bb218b185b63e3e92653953f29b6b143fb8cf5159fc908632e6fe490501"].to_vec(), hex!["1e0000000000000006000000000000000200000000000000"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b41dbd7d0b561a41d23c2a469ad42fbd70d5438bae826f6fd607413190c37c363b"].to_vec(), hex!["0500000000000000"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b46cddb367afbd583bb48f9bbd7d5ba3b1d0738b4881b1cddd38169526d8158137"].to_vec(), hex!["1e00000000000000"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b4b8788bb218b185b63e3e92653953f29b6b143fb8cf5159fc908632e6fe490501"].to_vec(), hex!["3c00000000000000"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b4e88b43fded6323ef02ffeffbd8c40846ee09bf316271bd22369659c959dd733a"].to_vec(), hex!["1400000000000000"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b4e96760d274653a39b429a87ebaae9d3aa4fdf58b9096cf0bebc7c4e5a4c2ed8d"].to_vec(), hex!["2800000000000000"].to_vec()), + (hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b4effb728943197fd12e694cbf3f3ede28fbf7498b0370c6dfa0013874b417c178"].to_vec(), hex!["3200000000000000"].to_vec()), + (hex!["f2794c22e353e9a839f12faab03a911b7f17cdfbfa73331856cca0acddd7842e"].to_vec(), hex!["00000000"].to_vec()), + (hex!["f2794c22e353e9a839f12faab03a911bbdcb0c5143a8617ed38ae3810dd45bc6"].to_vec(), hex!["00000000"].to_vec()), + (hex!["f2794c22e353e9a839f12faab03a911be2f6cb0456905c189bcb0458f9440f13"].to_vec(), hex!["00000000"].to_vec()), + ]; + s.top = data.into_iter().collect(); + sp_io::TestExternalities::new(s).execute_with(|| { + Balances::on_initialize(1); + assert_eq!(Balances::free_balance(&6), 60); + assert_eq!(Balances::usable_balance(&6), 30); + System::set_block_number(2); + assert_ok!(Vesting::vest(Origin::signed(6))); + assert_eq!(Balances::usable_balance(&6), 30); + System::set_block_number(3); + assert_ok!(Vesting::vest(Origin::signed(6))); + assert_eq!(Balances::usable_balance(&6), 36); + System::set_block_number(4); + assert_ok!(Vesting::vest(Origin::signed(6))); + assert_eq!(Balances::usable_balance(&6), 42); + }); + } + #[test] fn check_vesting_status() { ExtBuilder::default() From 7843d6b0227db541b90ea3f24d699a40d131ee86 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 26 Jan 2020 22:44:13 +0100 Subject: [PATCH 25/29] Fix --- frame/balances/src/migration.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/frame/balances/src/migration.rs b/frame/balances/src/migration.rs index 5be076d2b00eb..4748cf3913894 100644 --- a/frame/balances/src/migration.rs +++ b/frame/balances/src/migration.rs @@ -16,6 +16,7 @@ //! Some utilities for helping access storage with arbitrary key types. +use sp_std::prelude::*; use codec::{Encode, Decode}; use frame_support::{StorageHasher, Twox128}; From 89dcdc986854a255cbce3950bed4c0c063ad50d4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 27 Jan 2020 14:43:41 +0100 Subject: [PATCH 26/29] Indentation. --- frame/elections-phragmen/src/lib.rs | 2 +- frame/example/src/lib.rs | 2 +- frame/executive/src/lib.rs | 2 +- frame/identity/src/lib.rs | 2 +- frame/transaction-payment/src/lib.rs | 2 +- frame/treasury/src/lib.rs | 2 +- frame/utility/src/lib.rs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index bab6b153e23c1..6efac5cb759e9 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -821,7 +821,7 @@ mod tests { impl pallet_balances::Trait for Test { type Balance = u64; type OnNewAccount = (); -type OnReapAccount = System; + type OnReapAccount = System; type Event = Event; type TransferPayment = (); type DustRemoval = (); diff --git a/frame/example/src/lib.rs b/frame/example/src/lib.rs index 6463c33f499e4..92d83c608ba8a 100644 --- a/frame/example/src/lib.rs +++ b/frame/example/src/lib.rs @@ -693,7 +693,7 @@ mod tests { } impl pallet_balances::Trait for Test { type Balance = u64; -type OnReapAccount = System; + type OnReapAccount = System; type OnNewAccount = (); type Event = (); type TransferPayment = (); diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index cf4aafd9753db..281daaba5ce52 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -459,7 +459,7 @@ mod tests { } impl pallet_balances::Trait for Runtime { type Balance = u64; -type OnReapAccount = System; + type OnReapAccount = System; type OnNewAccount = (); type Event = MetaEvent; type DustRemoval = (); diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index a6eec63230246..b3ce015121bfd 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -918,7 +918,7 @@ mod tests { } impl pallet_balances::Trait for Test { type Balance = u64; -type OnReapAccount = System; + type OnReapAccount = System; type OnNewAccount = (); type Event = (); type TransferPayment = (); diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 0051c9a0bfe15..0c812a02ec029 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -310,7 +310,7 @@ mod tests { impl pallet_balances::Trait for Runtime { type Balance = u64; -type OnReapAccount = System; + type OnReapAccount = System; type OnNewAccount = (); type Event = (); type TransferPayment = (); diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index 739fe5a4c113d..2ce7a6362f7fc 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -764,7 +764,7 @@ mod tests { impl pallet_balances::Trait for Test { type Balance = u64; type OnNewAccount = (); -type OnReapAccount = System; + type OnReapAccount = System; type Event = (); type TransferPayment = (); type DustRemoval = (); diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index c1a5cf30ce240..a8269d934d54f 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -707,7 +707,7 @@ mod tests { } impl pallet_balances::Trait for Test { type Balance = u64; -type OnReapAccount = System; + type OnReapAccount = System; type OnNewAccount = (); type Event = TestEvent; type TransferPayment = (); From 050d44c2cc0beae37845b09bc1496b9ed8c6a375 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 27 Jan 2020 14:46:36 +0100 Subject: [PATCH 27/29] Undo unneeded referencing --- frame/balances/src/tests.rs | 104 ++++++++-------- frame/contracts/src/tests.rs | 22 ++-- frame/democracy/src/lib.rs | 88 ++++++------- frame/elections/src/tests.rs | 6 +- frame/identity/src/lib.rs | 26 ++-- frame/nicks/src/lib.rs | 16 +-- frame/recovery/src/tests.rs | 18 +-- frame/scored-pool/src/tests.rs | 14 +-- frame/society/src/tests.rs | 60 ++++----- frame/staking/src/tests.rs | 180 +++++++++++++-------------- frame/transaction-payment/src/lib.rs | 8 +- frame/treasury/src/lib.rs | 50 ++++---- frame/utility/src/lib.rs | 64 +++++----- frame/vesting/src/lib.rs | 2 +- 14 files changed, 329 insertions(+), 329 deletions(-) diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index 00b6af5a3f736..816768901b602 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -33,7 +33,7 @@ const ID_2: LockIdentifier = *b"2 "; #[test] fn basic_locking_should_work() { ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { - assert_eq!(Balances::free_balance(&1), 10); + assert_eq!(Balances::free_balance(1), 10); Balances::set_lock(ID_1, &1, 9, WithdrawReasons::all()); assert_noop!( >::transfer(&1, &2, 5, AllowDeath), @@ -217,7 +217,7 @@ fn default_indexing_on_new_accounts_should_not_work2() { Error::::ExistentialDeposit, ); assert_eq!(Balances::is_dead_account(&5), true); // account 5 should not exist - assert_eq!(Balances::free_balance(&1), 100); + assert_eq!(Balances::free_balance(1), 100); }); } @@ -234,7 +234,7 @@ fn reserved_balance_should_prevent_reclaim_count() { assert_eq!(Balances::total_balance(&2), 256 * 20); assert_ok!(Balances::reserve(&2, 256 * 19 + 1)); // account 2 becomes mostly reserved - assert_eq!(Balances::free_balance(&2), 255); // "free" account deleted." + assert_eq!(Balances::free_balance(2), 255); // "free" account deleted." assert_eq!(Balances::total_balance(&2), 256 * 20); // reserve still exists. assert_eq!(Balances::is_dead_account(&2), false); assert_eq!(System::account_nonce(&2), 1); @@ -309,11 +309,11 @@ fn dust_account_removal_should_work2() { fn balance_works() { ExtBuilder::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 42); - assert_eq!(Balances::free_balance(&1), 42); - assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Balances::free_balance(1), 42); + assert_eq!(Balances::reserved_balance(1), 0); assert_eq!(Balances::total_balance(&1), 42); - assert_eq!(Balances::free_balance(&2), 0); - assert_eq!(Balances::reserved_balance(&2), 0); + assert_eq!(Balances::free_balance(2), 0); + assert_eq!(Balances::reserved_balance(2), 0); assert_eq!(Balances::total_balance(&2), 0); }); } @@ -348,14 +348,14 @@ fn reserving_balance_should_work() { let _ = Balances::deposit_creating(&1, 111); assert_eq!(Balances::total_balance(&1), 111); - assert_eq!(Balances::free_balance(&1), 111); - assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Balances::free_balance(1), 111); + assert_eq!(Balances::reserved_balance(1), 0); assert_ok!(Balances::reserve(&1, 69)); assert_eq!(Balances::total_balance(&1), 111); - assert_eq!(Balances::free_balance(&1), 42); - assert_eq!(Balances::reserved_balance(&1), 69); + assert_eq!(Balances::free_balance(1), 42); + assert_eq!(Balances::reserved_balance(1), 69); }); } @@ -376,7 +376,7 @@ fn deducting_balance_should_work() { ExtBuilder::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 69)); - assert_eq!(Balances::free_balance(&1), 42); + assert_eq!(Balances::free_balance(1), 42); }); } @@ -387,8 +387,8 @@ fn refunding_balance_should_work() { let account = Balances::account(&1); Balances::set_account(&1, &AccountData { reserved: 69, ..account }, &account); Balances::unreserve(&1, 69); - assert_eq!(Balances::free_balance(&1), 111); - assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Balances::free_balance(1), 111); + assert_eq!(Balances::reserved_balance(1), 0); }); } @@ -398,8 +398,8 @@ fn slashing_balance_should_work() { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 69)); assert!(Balances::slash(&1, 69).1.is_zero()); - assert_eq!(Balances::free_balance(&1), 0); - assert_eq!(Balances::reserved_balance(&1), 42); + assert_eq!(Balances::free_balance(1), 0); + assert_eq!(Balances::reserved_balance(1), 42); assert_eq!(>::get(), 42); }); } @@ -410,8 +410,8 @@ fn slashing_incomplete_balance_should_work() { let _ = Balances::deposit_creating(&1, 42); assert_ok!(Balances::reserve(&1, 21)); assert_eq!(Balances::slash(&1, 69).1, 27); - assert_eq!(Balances::free_balance(&1), 0); - assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Balances::free_balance(1), 0); + assert_eq!(Balances::reserved_balance(1), 0); assert_eq!(>::get(), 0); }); } @@ -422,8 +422,8 @@ fn unreserving_balance_should_work() { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 111)); Balances::unreserve(&1, 42); - assert_eq!(Balances::reserved_balance(&1), 69); - assert_eq!(Balances::free_balance(&1), 42); + assert_eq!(Balances::reserved_balance(1), 69); + assert_eq!(Balances::free_balance(1), 42); }); } @@ -433,8 +433,8 @@ fn slashing_reserved_balance_should_work() { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 111)); assert_eq!(Balances::slash_reserved(&1, 42).1, 0); - assert_eq!(Balances::reserved_balance(&1), 69); - assert_eq!(Balances::free_balance(&1), 0); + assert_eq!(Balances::reserved_balance(1), 69); + assert_eq!(Balances::free_balance(1), 0); assert_eq!(>::get(), 69); }); } @@ -445,8 +445,8 @@ fn slashing_incomplete_reserved_balance_should_work() { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 42)); assert_eq!(Balances::slash_reserved(&1, 69).1, 27); - assert_eq!(Balances::free_balance(&1), 69); - assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Balances::free_balance(1), 69); + assert_eq!(Balances::reserved_balance(1), 0); assert_eq!(>::get(), 69); }); } @@ -458,10 +458,10 @@ fn transferring_reserved_balance_should_work() { let _ = Balances::deposit_creating(&2, 1); assert_ok!(Balances::reserve(&1, 110)); assert_ok!(Balances::repatriate_reserved(&1, &2, 41), 0); - assert_eq!(Balances::reserved_balance(&1), 69); - assert_eq!(Balances::free_balance(&1), 0); - assert_eq!(Balances::reserved_balance(&2), 0); - assert_eq!(Balances::free_balance(&2), 42); + assert_eq!(Balances::reserved_balance(1), 69); + assert_eq!(Balances::free_balance(1), 0); + assert_eq!(Balances::reserved_balance(2), 0); + assert_eq!(Balances::free_balance(2), 42); }); } @@ -481,10 +481,10 @@ fn transferring_incomplete_reserved_balance_should_work() { let _ = Balances::deposit_creating(&2, 1); assert_ok!(Balances::reserve(&1, 41)); assert_ok!(Balances::repatriate_reserved(&1, &2, 69), 28); - assert_eq!(Balances::reserved_balance(&1), 0); - assert_eq!(Balances::free_balance(&1), 69); - assert_eq!(Balances::reserved_balance(&2), 0); - assert_eq!(Balances::free_balance(&2), 42); + assert_eq!(Balances::reserved_balance(1), 0); + assert_eq!(Balances::free_balance(1), 69); + assert_eq!(Balances::reserved_balance(2), 0); + assert_eq!(Balances::free_balance(2), 42); }); } @@ -499,8 +499,8 @@ fn transferring_too_high_value_should_not_panic() { Error::::Overflow, ); - assert_eq!(Balances::free_balance(&1), u64::max_value()); - assert_eq!(Balances::free_balance(&2), 1); + assert_eq!(Balances::free_balance(1), u64::max_value()); + assert_eq!(Balances::free_balance(2), 1); }); } @@ -512,7 +512,7 @@ fn account_create_on_free_too_low_with_other() { // No-op. let _ = Balances::deposit_creating(&2, 50); - assert_eq!(Balances::free_balance(&2), 0); + assert_eq!(Balances::free_balance(2), 0); assert_eq!(>::get(), 100); }) } @@ -523,7 +523,7 @@ fn account_create_on_free_too_low() { ExtBuilder::default().existential_deposit(100).build().execute_with(|| { // No-op. let _ = Balances::deposit_creating(&2, 50); - assert_eq!(Balances::free_balance(&2), 0); + assert_eq!(Balances::free_balance(2), 0); assert_eq!(>::get(), 0); }) } @@ -537,8 +537,8 @@ fn account_removal_on_free_too_low() { let _ = Balances::deposit_creating(&1, 110); let _ = Balances::deposit_creating(&2, 110); - assert_eq!(Balances::free_balance(&1), 110); - assert_eq!(Balances::free_balance(&2), 110); + assert_eq!(Balances::free_balance(1), 110); + assert_eq!(Balances::free_balance(2), 110); assert_eq!(>::get(), 220); // Transfer funds from account 1 of such amount that after this transfer @@ -547,8 +547,8 @@ fn account_removal_on_free_too_low() { assert_ok!(Balances::transfer(Some(1).into(), 2, 20)); // Verify free balance removal of account 1. - assert_eq!(Balances::free_balance(&1), 0); - assert_eq!(Balances::free_balance(&2), 130); + assert_eq!(Balances::free_balance(1), 0); + assert_eq!(Balances::free_balance(2), 130); // Verify that TotalIssuance tracks balance removal when free balance is too low. assert_eq!(>::get(), 130); @@ -612,26 +612,26 @@ fn dust_moves_between_free_and_reserved() { // Set balance to free and reserved at the existential deposit assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 100, 0)); // Check balance - assert_eq!(Balances::free_balance(&1), 100); - assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Balances::free_balance(1), 100); + assert_eq!(Balances::reserved_balance(1), 0); // Reserve some free balance assert_ok!(Balances::reserve(&1, 50)); // Check balance, the account should be ok. - assert_eq!(Balances::free_balance(&1), 50); - assert_eq!(Balances::reserved_balance(&1), 50); + assert_eq!(Balances::free_balance(1), 50); + assert_eq!(Balances::reserved_balance(1), 50); // Reserve the rest of the free balance assert_ok!(Balances::reserve(&1, 50)); // Check balance, the account should be ok. - assert_eq!(Balances::free_balance(&1), 0); - assert_eq!(Balances::reserved_balance(&1), 100); + assert_eq!(Balances::free_balance(1), 0); + assert_eq!(Balances::reserved_balance(1), 100); // Unreserve everything Balances::unreserve(&1, 100); // Check balance, all 100 should move to free_balance - assert_eq!(Balances::free_balance(&1), 100); - assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Balances::free_balance(1), 100); + assert_eq!(Balances::reserved_balance(1), 0); }); } @@ -644,14 +644,14 @@ fn account_deleted_when_just_dust() { // Set balance to free and reserved at the existential deposit assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 50, 50)); // Check balance - assert_eq!(Balances::free_balance(&1), 50); - assert_eq!(Balances::reserved_balance(&1), 50); + assert_eq!(Balances::free_balance(1), 50); + assert_eq!(Balances::reserved_balance(1), 50); // Reserve some free balance let _ = Balances::slash(&1, 1); // The account should be dead. assert!(Balances::is_dead_account(&1)); - assert_eq!(Balances::free_balance(&1), 0); - assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Balances::free_balance(1), 0); + assert_eq!(Balances::reserved_balance(1), 0); }); } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 2256921287654..5eb7bce48ab3f 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -307,7 +307,7 @@ fn refunds_unused_gas() { assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, Vec::new())); // 2 * 135 - gas price multiplied by the call base fee. - assert_eq!(Balances::free_balance(&ALICE), 100_000_000 - (2 * 135)); + assert_eq!(Balances::free_balance(ALICE), 100_000_000 - (2 * 135)); }); } @@ -1014,7 +1014,7 @@ fn removals(trigger_call: impl Fn() -> bool) { // Trigger rent must have no effect assert!(trigger_call()); assert_eq!(ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 1_000); - assert_eq!(Balances::free_balance(&BOB), 100); + assert_eq!(Balances::free_balance(BOB), 100); // Advance blocks initialize_block(10); @@ -1022,7 +1022,7 @@ fn removals(trigger_call: impl Fn() -> bool) { // Trigger rent through call assert!(trigger_call()); assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); - assert_eq!(Balances::free_balance(&BOB), subsistence_threshold); + assert_eq!(Balances::free_balance(BOB), subsistence_threshold); // Advance blocks initialize_block(20); @@ -1030,7 +1030,7 @@ fn removals(trigger_call: impl Fn() -> bool) { // Trigger rent must have no effect assert!(trigger_call()); assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); - assert_eq!(Balances::free_balance(&BOB), subsistence_threshold); + assert_eq!(Balances::free_balance(BOB), subsistence_threshold); }); // Allowance exceeded @@ -1048,7 +1048,7 @@ fn removals(trigger_call: impl Fn() -> bool) { // Trigger rent must have no effect assert!(trigger_call()); assert_eq!(ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 100); - assert_eq!(Balances::free_balance(&BOB), 1_000); + assert_eq!(Balances::free_balance(BOB), 1_000); // Advance blocks initialize_block(10); @@ -1057,7 +1057,7 @@ fn removals(trigger_call: impl Fn() -> bool) { assert!(trigger_call()); assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); // Balance should be initial balance - initial rent_allowance - assert_eq!(Balances::free_balance(&BOB), 900); + assert_eq!(Balances::free_balance(BOB), 900); // Advance blocks initialize_block(20); @@ -1065,7 +1065,7 @@ fn removals(trigger_call: impl Fn() -> bool) { // Trigger rent must have no effect assert!(trigger_call()); assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); - assert_eq!(Balances::free_balance(&BOB), 900); + assert_eq!(Balances::free_balance(BOB), 900); }); // Balance reached and inferior to subsistence threshold @@ -1083,12 +1083,12 @@ fn removals(trigger_call: impl Fn() -> bool) { // Trigger rent must have no effect assert!(trigger_call()); assert_eq!(ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 1_000); - assert_eq!(Balances::free_balance(&BOB), 50 + Balances::minimum_balance()); + assert_eq!(Balances::free_balance(BOB), 50 + Balances::minimum_balance()); // Transfer funds assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::transfer())); assert_eq!(ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 1_000); - assert_eq!(Balances::free_balance(&BOB), Balances::minimum_balance()); + assert_eq!(Balances::free_balance(BOB), Balances::minimum_balance()); // Advance blocks initialize_block(10); @@ -1096,7 +1096,7 @@ fn removals(trigger_call: impl Fn() -> bool) { // Trigger rent through call assert!(trigger_call()); assert!(ContractInfoOf::::get(BOB).is_none()); - assert_eq!(Balances::free_balance(&BOB), Balances::minimum_balance()); + assert_eq!(Balances::free_balance(BOB), Balances::minimum_balance()); // Advance blocks initialize_block(20); @@ -1104,7 +1104,7 @@ fn removals(trigger_call: impl Fn() -> bool) { // Trigger rent must have no effect assert!(trigger_call()); assert!(ContractInfoOf::::get(BOB).is_none()); - assert_eq!(Balances::free_balance(&BOB), Balances::minimum_balance()); + assert_eq!(Balances::free_balance(BOB), Balances::minimum_balance()); }); } diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index c7f80f0c3d56b..5b954635afbdd 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -1331,12 +1331,12 @@ mod tests { s.top = data.into_iter().collect(); sp_io::TestExternalities::new(s).execute_with(|| { Balances::on_initialize(1); - assert_eq!(Balances::free_balance(&1), 5); - assert_eq!(Balances::reserved_balance(&1), 5); + assert_eq!(Balances::free_balance(1), 5); + assert_eq!(Balances::reserved_balance(1), 5); assert_eq!(Balances::usable_balance(&1), 2); assert_eq!(Balances::usable_balance_for_fees(&1), 5); - assert_eq!(Balances::free_balance(&2), 20); - assert_eq!(Balances::reserved_balance(&2), 0); + assert_eq!(Balances::free_balance(2), 20); + assert_eq!(Balances::reserved_balance(2), 0); assert_eq!(Balances::usable_balance(&2), 0); assert_eq!(Balances::usable_balance_for_fees(&2), 17); fast_forward_to(5); @@ -1349,7 +1349,7 @@ mod tests { fn params_should_work() { new_test_ext().execute_with(|| { assert_eq!(Democracy::referendum_count(), 0); - assert_eq!(Balances::free_balance(&42), 0); + assert_eq!(Balances::free_balance(42), 0); assert_eq!(Balances::total_issuance(), 210); }); } @@ -1415,7 +1415,7 @@ mod tests { next_block(); next_block(); - assert_eq!(Balances::free_balance(&42), 0); + assert_eq!(Balances::free_balance(42), 0); }); } @@ -1439,14 +1439,14 @@ mod tests { ); assert_ok!(Democracy::vote(Origin::signed(1), r, AYE)); - assert_eq!(Balances::reserved_balance(&6), 12); + assert_eq!(Balances::reserved_balance(6), 12); next_block(); next_block(); - assert_eq!(Balances::reserved_balance(&6), 0); - assert_eq!(Balances::free_balance(&6), 60); - assert_eq!(Balances::free_balance(&42), 2); + assert_eq!(Balances::reserved_balance(6), 0); + assert_eq!(Balances::free_balance(6), 60); + assert_eq!(Balances::free_balance(42), 2); }); } @@ -1457,7 +1457,7 @@ mod tests { PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1); assert_ok!(Democracy::note_preimage(Origin::signed(6), set_balance_proposal(2))); - assert_eq!(Balances::reserved_balance(&6), 12); + assert_eq!(Balances::reserved_balance(6), 12); next_block(); assert_noop!( @@ -1467,8 +1467,8 @@ mod tests { next_block(); assert_ok!(Democracy::reap_preimage(Origin::signed(6), set_balance_proposal_hash(2))); - assert_eq!(Balances::free_balance(&6), 60); - assert_eq!(Balances::reserved_balance(&6), 0); + assert_eq!(Balances::free_balance(6), 60); + assert_eq!(Balances::reserved_balance(6), 0); }); } @@ -1483,7 +1483,7 @@ mod tests { PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1); assert_ok!(Democracy::note_preimage(Origin::signed(6), set_balance_proposal(2))); - assert_eq!(Balances::reserved_balance(&6), 12); + assert_eq!(Balances::reserved_balance(6), 12); next_block(); next_block(); @@ -1495,9 +1495,9 @@ mod tests { next_block(); assert_ok!(Democracy::reap_preimage(Origin::signed(5), set_balance_proposal_hash(2))); - assert_eq!(Balances::reserved_balance(&6), 0); - assert_eq!(Balances::free_balance(&6), 48); - assert_eq!(Balances::free_balance(&5), 62); + assert_eq!(Balances::reserved_balance(6), 0); + assert_eq!(Balances::free_balance(6), 48); + assert_eq!(Balances::free_balance(5), 62); }); } @@ -1527,7 +1527,7 @@ mod tests { next_block(); - assert_eq!(Balances::free_balance(&42), 2); + assert_eq!(Balances::free_balance(42), 2); }); } @@ -1931,7 +1931,7 @@ mod tests { // referendum passes and wait another two blocks for enactment. fast_forward_to(6); - assert_eq!(Balances::free_balance(&42), 2); + assert_eq!(Balances::free_balance(42), 2); }); } @@ -2004,7 +2004,7 @@ mod tests { assert_eq!(Democracy::tally(r), (1, 0, 1)); fast_forward_to(6); - assert_eq!(Balances::free_balance(&42), 2); + assert_eq!(Balances::free_balance(42), 2); }); } @@ -2029,7 +2029,7 @@ mod tests { fast_forward_to(6); - assert_eq!(Balances::free_balance(&42), 2); + assert_eq!(Balances::free_balance(42), 2); }); } @@ -2055,7 +2055,7 @@ mod tests { fast_forward_to(6); - assert_eq!(Balances::free_balance(&42), 2); + assert_eq!(Balances::free_balance(42), 2); }); } @@ -2082,7 +2082,7 @@ mod tests { fast_forward_to(6); - assert_eq!(Balances::free_balance(&42), 2); + assert_eq!(Balances::free_balance(42), 2); }); } @@ -2110,7 +2110,7 @@ mod tests { fast_forward_to(6); - assert_eq!(Balances::free_balance(&42), 2); + assert_eq!(Balances::free_balance(42), 2); }); } @@ -2142,7 +2142,7 @@ mod tests { fast_forward_to(6); - assert_eq!(Balances::free_balance(&42), 2); + assert_eq!(Balances::free_balance(42), 2); }); } @@ -2155,9 +2155,9 @@ mod tests { assert_ok!(Democracy::second(Origin::signed(5), 0)); assert_ok!(Democracy::second(Origin::signed(5), 0)); assert_ok!(Democracy::second(Origin::signed(5), 0)); - assert_eq!(Balances::free_balance(&1), 5); - assert_eq!(Balances::free_balance(&2), 15); - assert_eq!(Balances::free_balance(&5), 35); + assert_eq!(Balances::free_balance(1), 5); + assert_eq!(Balances::free_balance(2), 15); + assert_eq!(Balances::free_balance(5), 35); }); } @@ -2171,9 +2171,9 @@ mod tests { assert_ok!(Democracy::second(Origin::signed(5), 0)); assert_ok!(Democracy::second(Origin::signed(5), 0)); fast_forward_to(3); - assert_eq!(Balances::free_balance(&1), 10); - assert_eq!(Balances::free_balance(&2), 20); - assert_eq!(Balances::free_balance(&5), 50); + assert_eq!(Balances::free_balance(1), 10); + assert_eq!(Balances::free_balance(2), 20); + assert_eq!(Balances::free_balance(5), 50); }); } @@ -2241,7 +2241,7 @@ mod tests { assert_eq!(Democracy::tally(r2), (1, 0, 1)); next_block(); - assert_eq!(Balances::free_balance(&42), 2); + assert_eq!(Balances::free_balance(42), 2); assert_ok!(Democracy::vote(Origin::signed(1), r1, AYE)); assert_eq!(Democracy::voters_for(r1), vec![1]); @@ -2249,7 +2249,7 @@ mod tests { assert_eq!(Democracy::tally(r1), (1, 0, 1)); next_block(); - assert_eq!(Balances::free_balance(&42), 3); + assert_eq!(Balances::free_balance(42), 3); }); } @@ -2272,7 +2272,7 @@ mod tests { next_block(); next_block(); - assert_eq!(Balances::free_balance(&42), 2); + assert_eq!(Balances::free_balance(42), 2); }); } @@ -2292,7 +2292,7 @@ mod tests { next_block(); next_block(); - assert_eq!(Balances::free_balance(&42), 0); + assert_eq!(Balances::free_balance(42), 0); }); } @@ -2315,7 +2315,7 @@ mod tests { next_block(); next_block(); - assert_eq!(Balances::free_balance(&42), 0); + assert_eq!(Balances::free_balance(42), 0); }); } @@ -2342,7 +2342,7 @@ mod tests { next_block(); next_block(); - assert_eq!(Balances::free_balance(&42), 2); + assert_eq!(Balances::free_balance(42), 2); }); } @@ -2366,11 +2366,11 @@ mod tests { assert_eq!(Democracy::tally(r), (21, 0, 21)); next_block(); - assert_eq!(Balances::free_balance(&42), 0); + assert_eq!(Balances::free_balance(42), 0); next_block(); - assert_eq!(Balances::free_balance(&42), 2); + assert_eq!(Balances::free_balance(42), 2); }); } @@ -2392,14 +2392,14 @@ mod tests { next_block(); next_block(); - assert_eq!(Balances::free_balance(&42), 0); + assert_eq!(Balances::free_balance(42), 0); }); } #[test] fn passing_low_turnout_voting_should_work() { new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(&42), 0); + assert_eq!(Balances::free_balance(42), 0); assert_eq!(Balances::total_issuance(), 210); System::set_block_number(1); @@ -2418,7 +2418,7 @@ mod tests { next_block(); next_block(); - assert_eq!(Balances::free_balance(&42), 2); + assert_eq!(Balances::free_balance(42), 2); }); } @@ -2478,7 +2478,7 @@ mod tests { assert_eq!(Democracy::locks(4), Some(6)); assert_eq!(Balances::locks(5), vec![]); - assert_eq!(Balances::free_balance(&42), 2); + assert_eq!(Balances::free_balance(42), 2); assert_noop!(Democracy::unlock(Origin::signed(1), 1), Error::::NotLocked); @@ -2535,7 +2535,7 @@ mod tests { next_block(); next_block(); - assert_eq!(Balances::free_balance(&42), 2); + assert_eq!(Balances::free_balance(42), 2); }); } } diff --git a/frame/elections/src/tests.rs b/frame/elections/src/tests.rs index 48161bcee49ac..e26f0312903fc 100644 --- a/frame/elections/src/tests.rs +++ b/frame/elections/src/tests.rs @@ -1179,14 +1179,14 @@ fn election_present_when_presenter_is_poor_should_not_work() { // -3 assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); - assert_eq!(Balances::free_balance(&1), 12); + assert_eq!(Balances::free_balance(1), 12); // -2 -5 assert_ok!(Elections::set_approvals(Origin::signed(1), vec![true], 0, 0, 15)); assert_ok!(Elections::end_block(System::block_number())); System::set_block_number(6); - assert_eq!(Balances::free_balance(&1), 5); - assert_eq!(Balances::reserved_balance(&1), 5); + assert_eq!(Balances::free_balance(1), 5); + assert_eq!(Balances::reserved_balance(1), 5); if p > 5 { assert_noop!(Elections::present_winner( Origin::signed(1), 1, 10, 0), diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index b3ce015121bfd..78f037c7339cf 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -1007,9 +1007,9 @@ mod tests { assert_ok!(Identity::set_fee(Origin::signed(3), 0, 10)); assert_ok!(Identity::set_identity(Origin::signed(10), ten())); assert_eq!(Identity::identity(10).unwrap().info, ten()); - assert_eq!(Balances::free_balance(&10), 90); + assert_eq!(Balances::free_balance(10), 90); assert_ok!(Identity::clear_identity(Origin::signed(10))); - assert_eq!(Balances::free_balance(&10), 100); + assert_eq!(Balances::free_balance(10), 100); assert_noop!(Identity::clear_identity(Origin::signed(10)), Error::::NotNamed); }); } @@ -1061,7 +1061,7 @@ mod tests { assert_noop!(Identity::kill_identity(Origin::signed(1), 10), BadOrigin); assert_ok!(Identity::kill_identity(Origin::signed(2), 10)); assert_eq!(Identity::identity(10), None); - assert_eq!(Balances::free_balance(&10), 90); + assert_eq!(Balances::free_balance(10), 90); assert_noop!(Identity::kill_identity(Origin::signed(2), 10), Error::::NotNamed); }); } @@ -1074,14 +1074,14 @@ mod tests { assert_ok!(Identity::set_identity(Origin::signed(10), ten())); assert_ok!(Identity::set_subs(Origin::signed(10), subs.clone())); - assert_eq!(Balances::free_balance(&10), 80); + assert_eq!(Balances::free_balance(10), 80); assert_eq!(Identity::subs(10), (10, vec![20])); assert_eq!(Identity::super_of(20), Some((10, Data::Raw(vec![40; 1])))); // push another item and re-set it. subs.push((30, Data::Raw(vec![50; 1]))); assert_ok!(Identity::set_subs(Origin::signed(10), subs.clone())); - assert_eq!(Balances::free_balance(&10), 70); + assert_eq!(Balances::free_balance(10), 70); assert_eq!(Identity::subs(10), (20, vec![20, 30])); assert_eq!(Identity::super_of(20), Some((10, Data::Raw(vec![40; 1])))); assert_eq!(Identity::super_of(30), Some((10, Data::Raw(vec![50; 1])))); @@ -1089,7 +1089,7 @@ mod tests { // switch out one of the items and re-set. subs[0] = (40, Data::Raw(vec![60; 1])); assert_ok!(Identity::set_subs(Origin::signed(10), subs.clone())); - assert_eq!(Balances::free_balance(&10), 70); // no change in the balance + assert_eq!(Balances::free_balance(10), 70); // no change in the balance assert_eq!(Identity::subs(10), (20, vec![40, 30])); assert_eq!(Identity::super_of(20), None); assert_eq!(Identity::super_of(30), Some((10, Data::Raw(vec![50; 1])))); @@ -1097,7 +1097,7 @@ mod tests { // clear assert_ok!(Identity::set_subs(Origin::signed(10), vec![])); - assert_eq!(Balances::free_balance(&10), 90); + assert_eq!(Balances::free_balance(10), 90); assert_eq!(Identity::subs(10), (0, vec![])); assert_eq!(Identity::super_of(30), None); assert_eq!(Identity::super_of(40), None); @@ -1113,7 +1113,7 @@ mod tests { assert_ok!(Identity::set_identity(Origin::signed(10), ten())); assert_ok!(Identity::set_subs(Origin::signed(10), vec![(20, Data::Raw(vec![40; 1]))])); assert_ok!(Identity::clear_identity(Origin::signed(10))); - assert_eq!(Balances::free_balance(&10), 100); + assert_eq!(Balances::free_balance(10), 100); assert!(Identity::super_of(20).is_none()); }); } @@ -1124,7 +1124,7 @@ mod tests { assert_ok!(Identity::set_identity(Origin::signed(10), ten())); assert_ok!(Identity::set_subs(Origin::signed(10), vec![(20, Data::Raw(vec![40; 1]))])); assert_ok!(Identity::kill_identity(Origin::ROOT, 10)); - assert_eq!(Balances::free_balance(&10), 80); + assert_eq!(Balances::free_balance(10), 80); assert!(Identity::super_of(20).is_none()); }); } @@ -1138,7 +1138,7 @@ mod tests { assert_ok!(Identity::set_identity(Origin::signed(10), ten())); assert_ok!(Identity::request_judgement(Origin::signed(10), 0, 10)); assert_ok!(Identity::cancel_request(Origin::signed(10), 0)); - assert_eq!(Balances::free_balance(&10), 90); + assert_eq!(Balances::free_balance(10), 90); assert_noop!(Identity::cancel_request(Origin::signed(10), 0), Error::::NotFound); assert_ok!(Identity::provide_judgement(Origin::signed(3), 0, 10, Judgement::Reasonable)); @@ -1155,13 +1155,13 @@ mod tests { assert_noop!(Identity::request_judgement(Origin::signed(10), 0, 9), Error::::FeeChanged); assert_ok!(Identity::request_judgement(Origin::signed(10), 0, 10)); // 10 for the judgement request, 10 for the identity. - assert_eq!(Balances::free_balance(&10), 80); + assert_eq!(Balances::free_balance(10), 80); // Re-requesting won't work as we already paid. assert_noop!(Identity::request_judgement(Origin::signed(10), 0, 10), Error::::StickyJudgement); assert_ok!(Identity::provide_judgement(Origin::signed(3), 0, 10, Judgement::Erroneous)); // Registrar got their payment now. - assert_eq!(Balances::free_balance(&3), 20); + assert_eq!(Balances::free_balance(3), 20); // Re-requesting still won't work as it's erroneous. assert_noop!(Identity::request_judgement(Origin::signed(10), 0, 10), Error::::StickyJudgement); @@ -1187,7 +1187,7 @@ mod tests { (Data::Raw(b"text".to_vec()), Data::Raw(b"10".to_vec())), ], .. Default::default() })); - assert_eq!(Balances::free_balance(&10), 70); + assert_eq!(Balances::free_balance(10), 70); }); } diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index ec696dc6a843c..3da5d35f55a3a 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -355,9 +355,9 @@ mod tests { ); assert_ok!(Nicks::set_name(Origin::signed(2), b"Dave".to_vec())); - assert_eq!(Balances::reserved_balance(&2), 2); + assert_eq!(Balances::reserved_balance(2), 2); assert_ok!(Nicks::force_name(Origin::signed(1), 2, b"Dr. David Brubeck, III".to_vec())); - assert_eq!(Balances::reserved_balance(&2), 2); + assert_eq!(Balances::reserved_balance(2), 2); assert_eq!(>::get(2).unwrap(), (b"Dr. David Brubeck, III".to_vec(), 2)); }); } @@ -366,18 +366,18 @@ mod tests { fn normal_operation_should_work() { new_test_ext().execute_with(|| { assert_ok!(Nicks::set_name(Origin::signed(1), b"Gav".to_vec())); - assert_eq!(Balances::reserved_balance(&1), 2); - assert_eq!(Balances::free_balance(&1), 8); + assert_eq!(Balances::reserved_balance(1), 2); + assert_eq!(Balances::free_balance(1), 8); assert_eq!(>::get(1).unwrap().0, b"Gav".to_vec()); assert_ok!(Nicks::set_name(Origin::signed(1), b"Gavin".to_vec())); - assert_eq!(Balances::reserved_balance(&1), 2); - assert_eq!(Balances::free_balance(&1), 8); + assert_eq!(Balances::reserved_balance(1), 2); + assert_eq!(Balances::free_balance(1), 8); assert_eq!(>::get(1).unwrap().0, b"Gavin".to_vec()); assert_ok!(Nicks::clear_name(Origin::signed(1))); - assert_eq!(Balances::reserved_balance(&1), 0); - assert_eq!(Balances::free_balance(&1), 10); + assert_eq!(Balances::reserved_balance(1), 0); + assert_eq!(Balances::free_balance(1), 10); }); } diff --git a/frame/recovery/src/tests.rs b/frame/recovery/src/tests.rs index c9586dce849fe..cfc8e25b125a0 100644 --- a/frame/recovery/src/tests.rs +++ b/frame/recovery/src/tests.rs @@ -35,7 +35,7 @@ fn basic_setup_works() { assert_eq!(Recovery::active_recovery(&1, &2), None); assert_eq!(Recovery::recovery_config(&1), None); // Everyone should have starting balance of 100 - assert_eq!(Balances::free_balance(&1), 100); + assert_eq!(Balances::free_balance(1), 100); }); } @@ -50,8 +50,8 @@ fn set_recovered_works() { let call = Box::new(Call::Balances(BalancesCall::transfer(1, 100))); assert_ok!(Recovery::as_recovered(Origin::signed(1), 5, call)); // Account 1 has successfully drained the funds from account 5 - assert_eq!(Balances::free_balance(&1), 200); - assert_eq!(Balances::free_balance(&5), 0); + assert_eq!(Balances::free_balance(1), 200); + assert_eq!(Balances::free_balance(5), 0); }); } @@ -85,12 +85,12 @@ fn recovery_lifecycle_works() { let call = Box::new(Call::Recovery(RecoveryCall::remove_recovery())); assert_ok!(Recovery::as_recovered(Origin::signed(1), 5, call)); // Account 1 should now be able to make a call through account 5 to get all of their funds - assert_eq!(Balances::free_balance(&5), 110); + assert_eq!(Balances::free_balance(5), 110); let call = Box::new(Call::Balances(BalancesCall::transfer(1, 110))); assert_ok!(Recovery::as_recovered(Origin::signed(1), 5, call)); // All funds have been fully recovered! - assert_eq!(Balances::free_balance(&1), 200); - assert_eq!(Balances::free_balance(&5), 0); + assert_eq!(Balances::free_balance(1), 200); + assert_eq!(Balances::free_balance(5), 0); // All storage items are removed from the module assert!(!>::exists(&5, &1)); assert!(!>::exists(&5)); @@ -190,7 +190,7 @@ fn create_recovery_works() { assert_ok!(Recovery::create_recovery(Origin::signed(5), friends.clone(), threshold, delay_period)); // Deposit is taken, and scales with the number of friends they pick // Base 10 + 1 per friends = 13 total reserved - assert_eq!(Balances::reserved_balance(&5), 13); + assert_eq!(Balances::reserved_balance(5), 13); // Recovery configuration is correctly stored let recovery_config = RecoveryConfig { delay_period, @@ -219,7 +219,7 @@ fn initiate_recovery_handles_basic_errors() { assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); assert_noop!(Recovery::initiate_recovery(Origin::signed(1), 5), Error::::AlreadyStarted); // No double deposit - assert_eq!(Balances::reserved_balance(&1), 10); + assert_eq!(Balances::reserved_balance(1), 10); }); } @@ -234,7 +234,7 @@ fn initiate_recovery_works() { // Recovery can be initiated assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); // Deposit is reserved - assert_eq!(Balances::reserved_balance(&1), 10); + assert_eq!(Balances::reserved_balance(1), 10); // Recovery status object is created correctly let recovery_status = ActiveRecovery { created: 1, diff --git a/frame/scored-pool/src/tests.rs b/frame/scored-pool/src/tests.rs index d8c887f4ec683..4b21339505ded 100644 --- a/frame/scored-pool/src/tests.rs +++ b/frame/scored-pool/src/tests.rs @@ -30,8 +30,8 @@ type Balances = pallet_balances::Module; fn query_membership_works() { new_test_ext().execute_with(|| { assert_eq!(ScoredPool::members(), vec![20, 40]); - assert_eq!(Balances::reserved_balance(&31), CandidateDeposit::get()); - assert_eq!(Balances::reserved_balance(&40), CandidateDeposit::get()); + assert_eq!(Balances::reserved_balance(31), CandidateDeposit::get()); + assert_eq!(Balances::reserved_balance(40), CandidateDeposit::get()); assert_eq!(MEMBERS.with(|m| m.borrow().clone()), vec![20, 40]); }); } @@ -61,7 +61,7 @@ fn submit_candidacy_works() { assert_eq!(fetch_from_pool(15), Some((who, None))); // then - assert_eq!(Balances::reserved_balance(&who), CandidateDeposit::get()); + assert_eq!(Balances::reserved_balance(who), CandidateDeposit::get()); }); } @@ -117,7 +117,7 @@ fn kicking_works() { new_test_ext().execute_with(|| { // given let who = 40; - assert_eq!(Balances::reserved_balance(&who), CandidateDeposit::get()); + assert_eq!(Balances::reserved_balance(who), CandidateDeposit::get()); assert_eq!(find_in_pool(who), Some(0)); // when @@ -128,7 +128,7 @@ fn kicking_works() { assert_eq!(find_in_pool(who), None); assert_eq!(ScoredPool::members(), vec![20, 31]); assert_eq!(MEMBERS.with(|m| m.borrow().clone()), ScoredPool::members()); - assert_eq!(Balances::reserved_balance(&who), 0); // deposit must have been returned + assert_eq!(Balances::reserved_balance(who), 0); // deposit must have been returned }); } @@ -246,7 +246,7 @@ fn withdraw_scored_candidacy_must_work() { new_test_ext().execute_with(|| { // given let who = 40; - assert_eq!(Balances::reserved_balance(&who), CandidateDeposit::get()); + assert_eq!(Balances::reserved_balance(who), CandidateDeposit::get()); // when let index = find_in_pool(who).expect("entity must be in pool") as u32; @@ -255,7 +255,7 @@ fn withdraw_scored_candidacy_must_work() { // then assert_eq!(fetch_from_pool(who), None); assert_eq!(ScoredPool::members(), vec![20, 31]); - assert_eq!(Balances::reserved_balance(&who), 0); + assert_eq!(Balances::reserved_balance(who), 0); }); } diff --git a/frame/society/src/tests.rs b/frame/society/src/tests.rs index 2d566e0f0e785..3e5afc47f500a 100644 --- a/frame/society/src/tests.rs +++ b/frame/society/src/tests.rs @@ -82,11 +82,11 @@ fn unfounding_works() { #[test] fn basic_new_member_works() { EnvBuilder::new().execute(|| { - assert_eq!(Balances::free_balance(&20), 50); + assert_eq!(Balances::free_balance(20), 50); // Bid causes Candidate Deposit to be reserved. assert_ok!(Society::bid(Origin::signed(20), 0)); - assert_eq!(Balances::free_balance(&20), 25); - assert_eq!(Balances::reserved_balance(&20), 25); + assert_eq!(Balances::free_balance(20), 25); + assert_eq!(Balances::reserved_balance(20), 25); // Rotate period every 4 blocks run_to_block(4); // 20 is now a candidate @@ -98,8 +98,8 @@ fn basic_new_member_works() { // 20 is now a member of the society assert_eq!(Society::members(), vec![10, 20]); // Reserved balance is returned - assert_eq!(Balances::free_balance(&20), 50); - assert_eq!(Balances::reserved_balance(&20), 0); + assert_eq!(Balances::free_balance(20), 50); + assert_eq!(Balances::reserved_balance(20), 0); }); } @@ -115,7 +115,7 @@ fn bidding_works() { run_to_block(4); // Pot is 1000 after "PeriodSpend" assert_eq!(Society::pot(), 1000); - assert_eq!(Balances::free_balance(&Society::account_id()), 10_000); + assert_eq!(Balances::free_balance(Society::account_id()), 10_000); // Choose smallest bidding users whose total is less than pot assert_eq!(Society::candidates(), vec![ create_bid(300, 30, BidKind::Deposit(25)), @@ -128,7 +128,7 @@ fn bidding_works() { // Candidates become members after a period rotation assert_eq!(Society::members(), vec![10, 30, 40]); // Pot is increased by 1000, but pays out 700 to the members - assert_eq!(Balances::free_balance(&Society::account_id()), 9_300); + assert_eq!(Balances::free_balance(Society::account_id()), 9_300); assert_eq!(Society::pot(), 1_300); // Left over from the original bids is 50 who satisfies the condition of bid less than pot. assert_eq!(Society::candidates(), vec![ create_bid(500, 50, BidKind::Deposit(25)) ]); @@ -139,7 +139,7 @@ fn bidding_works() { assert_eq!(Society::members(), vec![10, 30, 40, 50]); // Pot is increased by 1000, and 500 is paid out. Total payout so far is 1200. assert_eq!(Society::pot(), 1_800); - assert_eq!(Balances::free_balance(&Society::account_id()), 8_800); + assert_eq!(Balances::free_balance(Society::account_id()), 8_800); // No more candidates satisfy the requirements assert_eq!(Society::candidates(), vec![]); assert_ok!(Society::defender_vote(Origin::signed(10), true)); // Keep defender around @@ -150,7 +150,7 @@ fn bidding_works() { // Pot is increased by 1000 again assert_eq!(Society::pot(), 2_800); // No payouts - assert_eq!(Balances::free_balance(&Society::account_id()), 8_800); + assert_eq!(Balances::free_balance(Society::account_id()), 8_800); // Candidate 60 now qualifies based on the increased pot size. assert_eq!(Society::candidates(), vec![ create_bid(1900, 60, BidKind::Deposit(25)) ]); // Candidate 60 is voted in. @@ -160,7 +160,7 @@ fn bidding_works() { assert_eq!(Society::members(), vec![10, 30, 40, 50, 60]); // Pay them assert_eq!(Society::pot(), 1_900); - assert_eq!(Balances::free_balance(&Society::account_id()), 6_900); + assert_eq!(Balances::free_balance(Society::account_id()), 6_900); }); } @@ -171,15 +171,15 @@ fn unbidding_works() { assert_ok!(Society::bid(Origin::signed(20), 1000)); assert_ok!(Society::bid(Origin::signed(30), 0)); // Balances are reserved - assert_eq!(Balances::free_balance(&30), 25); - assert_eq!(Balances::reserved_balance(&30), 25); + assert_eq!(Balances::free_balance(30), 25); + assert_eq!(Balances::reserved_balance(30), 25); // Must know right position to unbid + cannot unbid someone else assert_noop!(Society::unbid(Origin::signed(30), 1), Error::::BadPosition); // Can unbid themselves with the right position assert_ok!(Society::unbid(Origin::signed(30), 0)); // Balance is returned - assert_eq!(Balances::free_balance(&30), 50); - assert_eq!(Balances::reserved_balance(&30), 0); + assert_eq!(Balances::free_balance(30), 50); + assert_eq!(Balances::reserved_balance(30), 0); // 20 wins candidacy run_to_block(4); assert_eq!(Society::candidates(), vec![ create_bid(1000, 20, BidKind::Deposit(25)) ]); @@ -190,7 +190,7 @@ fn unbidding_works() { fn payout_works() { EnvBuilder::new().execute(|| { // Original balance of 50 - assert_eq!(Balances::free_balance(&20), 50); + assert_eq!(Balances::free_balance(20), 50); assert_ok!(Society::bid(Origin::signed(20), 1000)); run_to_block(4); assert_ok!(Society::vote(Origin::signed(10), 20, true)); @@ -200,7 +200,7 @@ fn payout_works() { run_to_block(9); // payout should be here assert_ok!(Society::payout(Origin::signed(20))); - assert_eq!(Balances::free_balance(&20), 1050); + assert_eq!(Balances::free_balance(20), 1050); }); } @@ -221,11 +221,11 @@ fn basic_new_member_skeptic_works() { fn basic_new_member_reject_works() { EnvBuilder::new().execute(|| { // Starting Balance - assert_eq!(Balances::free_balance(&20), 50); + assert_eq!(Balances::free_balance(20), 50); // 20 makes a bid assert_ok!(Society::bid(Origin::signed(20), 0)); - assert_eq!(Balances::free_balance(&20), 25); - assert_eq!(Balances::reserved_balance(&20), 25); + assert_eq!(Balances::free_balance(20), 25); + assert_eq!(Balances::reserved_balance(20), 25); // Rotation Period run_to_block(4); assert_eq!(Society::candidates(), vec![create_bid(0, 20, BidKind::Deposit(25))]); @@ -243,7 +243,7 @@ fn basic_new_member_reject_works() { #[test] fn slash_payout_works() { EnvBuilder::new().execute(|| { - assert_eq!(Balances::free_balance(&20), 50); + assert_eq!(Balances::free_balance(20), 50); assert_ok!(Society::bid(Origin::signed(20), 1000)); run_to_block(4); assert_ok!(Society::vote(Origin::signed(10), 20, true)); @@ -257,14 +257,14 @@ fn slash_payout_works() { run_to_block(9); // payout should be here, but 500 less assert_ok!(Society::payout(Origin::signed(20))); - assert_eq!(Balances::free_balance(&20), 550); + assert_eq!(Balances::free_balance(20), 550); }); } #[test] fn slash_payout_multi_works() { EnvBuilder::new().execute(|| { - assert_eq!(Balances::free_balance(&20), 50); + assert_eq!(Balances::free_balance(20), 50); // create a few payouts Society::bump_payout(&20, 5, 100); Society::bump_payout(&20, 10, 100); @@ -330,12 +330,12 @@ fn suspended_member_lifecycle_works() { fn suspended_candidate_rejected_works() { EnvBuilder::new().execute(|| { // Starting Balance - assert_eq!(Balances::free_balance(&20), 50); - assert_eq!(Balances::free_balance(&Society::account_id()), 10000); + assert_eq!(Balances::free_balance(20), 50); + assert_eq!(Balances::free_balance(Society::account_id()), 10000); // 20 makes a bid assert_ok!(Society::bid(Origin::signed(20), 0)); - assert_eq!(Balances::free_balance(&20), 25); - assert_eq!(Balances::reserved_balance(&20), 25); + assert_eq!(Balances::free_balance(20), 25); + assert_eq!(Balances::reserved_balance(20), 25); // Rotation Period run_to_block(4); assert_eq!(Society::candidates(), vec![create_bid(0, 20, BidKind::Deposit(25))]); @@ -369,10 +369,10 @@ fn suspended_candidate_rejected_works() { // Suspension judgement origin rejects the candidate assert_ok!(Society::judge_suspended_candidate(Origin::signed(2), 20, Judgement::Reject)); // User is slashed - assert_eq!(Balances::free_balance(&20), 25); - assert_eq!(Balances::reserved_balance(&20), 0); + assert_eq!(Balances::free_balance(20), 25); + assert_eq!(Balances::reserved_balance(20), 0); // Funds are deposited to society account - assert_eq!(Balances::free_balance(&Society::account_id()), 10025); + assert_eq!(Balances::free_balance(Society::account_id()), 10025); // Cleaned up assert_eq!(Society::candidates(), vec![]); assert_eq!(>::get(20), None); @@ -837,7 +837,7 @@ fn zero_bid_works() { run_to_block(4); // Pot is 1000 after "PeriodSpend" assert_eq!(Society::pot(), 1000); - assert_eq!(Balances::free_balance(&Society::account_id()), 10_000); + assert_eq!(Balances::free_balance(Society::account_id()), 10_000); // Choose smallest bidding users whose total is less than pot, with only one zero bid. assert_eq!(Society::candidates(), vec![ create_bid(0, 30, BidKind::Deposit(25)), diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 43a2d0079164f..a9b6e16598a2b 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -110,8 +110,8 @@ fn basic_setup_works() { assert_eq!(Staking::current_era(), 0); // Account 10 has `balance_factor` free balance - assert_eq!(Balances::free_balance(&10), 1); - assert_eq!(Balances::free_balance(&10), 1); + assert_eq!(Balances::free_balance(10), 1); + assert_eq!(Balances::free_balance(10), 1); // New era is not being forced assert_eq!(Staking::force_era(), Forcing::NotForcing); @@ -759,7 +759,7 @@ fn cannot_transfer_staked_balance() { // Confirm account 11 is stashed assert_eq!(Staking::bonded(&11), Some(10)); // Confirm account 11 has some free balance - assert_eq!(Balances::free_balance(&11), 1000); + assert_eq!(Balances::free_balance(11), 1000); // Confirm account 11 (via controller 10) is totally staked assert_eq!(Staking::stakers(&11).total, 1000); // Confirm account 11 cannot transfer as a result @@ -788,7 +788,7 @@ fn cannot_transfer_staked_balance_2() { // Confirm account 21 is stashed assert_eq!(Staking::bonded(&21), Some(20)); // Confirm account 21 has some free balance - assert_eq!(Balances::free_balance(&21), 2000); + assert_eq!(Balances::free_balance(21), 2000); // Confirm account 21 (via controller 20) is totally staked assert_eq!(Staking::stakers(&21).total, 1000); // Confirm account 21 can transfer at most 1000 @@ -811,7 +811,7 @@ fn cannot_reserve_staked_balance() { // Confirm account 11 is stashed assert_eq!(Staking::bonded(&11), Some(10)); // Confirm account 11 has some free balance - assert_eq!(Balances::free_balance(&11), 1000); + assert_eq!(Balances::free_balance(11), 1000); // Confirm account 11 (via controller 10) is totally staked assert_eq!(Staking::stakers(&11).own, 1000); // Confirm account 11 cannot transfer as a result @@ -838,9 +838,9 @@ fn reward_destination_works() { // Check that account 11 is a validator assert!(Staking::current_elected().contains(&11)); // Check the balance of the validator account - assert_eq!(Balances::free_balance(&10), 1); + assert_eq!(Balances::free_balance(10), 1); // Check the balance of the stash account - assert_eq!(Balances::free_balance(&11), 1000); + assert_eq!(Balances::free_balance(11), 1000); // Check how much is at stake assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, @@ -859,7 +859,7 @@ fn reward_destination_works() { // Check that RewardDestination is Staked (default) assert_eq!(Staking::payee(&11), RewardDestination::Staked); // Check that reward went to the stash account of validator - assert_eq!(Balances::free_balance(&11), 1000 + total_payout_0); + assert_eq!(Balances::free_balance(11), 1000 + total_payout_0); // Check that amount at stake increased accordingly assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, @@ -881,7 +881,7 @@ fn reward_destination_works() { // Check that RewardDestination is Stash assert_eq!(Staking::payee(&11), RewardDestination::Stash); // Check that reward went to the stash account - assert_eq!(Balances::free_balance(&11), 1000 + total_payout_0 + total_payout_1); + assert_eq!(Balances::free_balance(11), 1000 + total_payout_0 + total_payout_1); // Record this value let recorded_stash_balance = 1000 + total_payout_0 + total_payout_1; // Check that amount at stake is NOT increased @@ -896,7 +896,7 @@ fn reward_destination_works() { >::insert(&11, RewardDestination::Controller); // Check controller balance - assert_eq!(Balances::free_balance(&10), 1); + assert_eq!(Balances::free_balance(10), 1); // Compute total payout now for whole duration as other parameter won't change let total_payout_2 = current_total_payout_for_duration(3000); @@ -908,7 +908,7 @@ fn reward_destination_works() { // Check that RewardDestination is Controller assert_eq!(Staking::payee(&11), RewardDestination::Controller); // Check that reward went to the controller account - assert_eq!(Balances::free_balance(&10), 1 + total_payout_2); + assert_eq!(Balances::free_balance(10), 1 + total_payout_2); // Check that amount at stake is NOT increased assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, @@ -917,7 +917,7 @@ fn reward_destination_works() { unlocking: vec![], })); // Check that amount in staked account is NOT increased. - assert_eq!(Balances::free_balance(&11), recorded_stash_balance); + assert_eq!(Balances::free_balance(11), recorded_stash_balance); }); } @@ -1422,9 +1422,9 @@ fn on_free_balance_zero_stash_removes_validator() { // Tests that storage items are untouched when controller is empty ExtBuilder::default().existential_deposit(10).build().execute_with(|| { // Check the balance of the validator account - assert_eq!(Balances::free_balance(&10), 256); + assert_eq!(Balances::free_balance(10), 256); // Check the balance of the stash account - assert_eq!(Balances::free_balance(&11), 256000); + assert_eq!(Balances::free_balance(11), 256000); // Check these two accounts are bonded assert_eq!(Staking::bonded(&11), Some(10)); @@ -1442,7 +1442,7 @@ fn on_free_balance_zero_stash_removes_validator() { let _ = Balances::slash(&10, u64::max_value()); // Check the balance of the stash account has not been touched - assert_eq!(Balances::free_balance(&11), 256000); + assert_eq!(Balances::free_balance(11), 256000); // Check these two accounts are still bonded assert_eq!(Staking::bonded(&11), Some(10)); @@ -1476,9 +1476,9 @@ fn on_free_balance_zero_stash_removes_nominator() { // Check that account 10 is a nominator assert!(>::exists(11)); // Check the balance of the nominator account - assert_eq!(Balances::free_balance(&10), 256); + assert_eq!(Balances::free_balance(10), 256); // Check the balance of the stash account - assert_eq!(Balances::free_balance(&11), 256000); + assert_eq!(Balances::free_balance(11), 256000); // Set payee information assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Stash)); @@ -1495,7 +1495,7 @@ fn on_free_balance_zero_stash_removes_nominator() { assert_eq!(Balances::total_balance(&10), 0); // Check the balance of the stash account has not been touched - assert_eq!(Balances::free_balance(&11), 256000); + assert_eq!(Balances::free_balance(11), 256000); // Check these two accounts are still bonded assert_eq!(Staking::bonded(&11), Some(10)); @@ -1689,9 +1689,9 @@ fn bond_with_little_staked_value_bounded_by_slot_stake() { assert_eq!(Staking::slot_stake(), 1); // Old ones are rewarded. - assert_eq!(Balances::free_balance(&10), init_balance_10 + total_payout_0 / 3); + assert_eq!(Balances::free_balance(10), init_balance_10 + total_payout_0 / 3); // no rewards paid to 2. This was initial election. - assert_eq!(Balances::free_balance(&2), init_balance_2); + assert_eq!(Balances::free_balance(2), init_balance_2); let total_payout_1 = current_total_payout_for_duration(3000); assert!(total_payout_1 > 100); // Test is meaningfull if reward something @@ -1701,7 +1701,7 @@ fn bond_with_little_staked_value_bounded_by_slot_stake() { assert_eq_uvec!(validator_controllers(), vec![20, 10, 2]); assert_eq!(Staking::slot_stake(), 1); - assert_eq!(Balances::free_balance(&2), init_balance_2 + total_payout_1 / 3); + assert_eq!(Balances::free_balance(2), init_balance_2 + total_payout_1 / 3); assert_eq!( Balances::free_balance(&10), init_balance_10 + total_payout_0 / 3 + total_payout_1 / 3, @@ -2008,7 +2008,7 @@ fn slashing_performed_according_exposure() { ); // The stash account should be slashed for 250 (50% of 500). - assert_eq!(Balances::free_balance(&11), 1000 - 250); + assert_eq!(Balances::free_balance(11), 1000 - 250); }); } @@ -2102,8 +2102,8 @@ fn reporters_receive_their_slice() { // 50% * (10% * initial_balance / 2) let reward = (initial_balance / 20) / 2; let reward_each = reward / 2; // split into two pieces. - assert_eq!(Balances::free_balance(&1), 10 + reward_each); - assert_eq!(Balances::free_balance(&2), 20 + reward_each); + assert_eq!(Balances::free_balance(1), 10 + reward_each); + assert_eq!(Balances::free_balance(2), 20 + reward_each); assert_ledger_consistent(11); }); } @@ -2132,7 +2132,7 @@ fn subsequent_reports_in_same_span_pay_out_less() { // F1 * (reward_proportion * slash - 0) // 50% * (10% * initial_balance * 20%) let reward = (initial_balance / 5) / 20; - assert_eq!(Balances::free_balance(&1), 10 + reward); + assert_eq!(Balances::free_balance(1), 10 + reward); on_offence_now( &[OffenceDetails { @@ -2150,7 +2150,7 @@ fn subsequent_reports_in_same_span_pay_out_less() { // F1 * (reward_proportion * slash - prior_payout) // 50% * (10% * (initial_balance / 2) - prior_payout) let reward = ((initial_balance / 20) - prior_payout) / 2; - assert_eq!(Balances::free_balance(&1), 10 + prior_payout + reward); + assert_eq!(Balances::free_balance(1), 10 + prior_payout + reward); assert_ledger_consistent(11); }); } @@ -2159,8 +2159,8 @@ fn subsequent_reports_in_same_span_pay_out_less() { fn invulnerables_are_not_slashed() { // For invulnerable validators no slashing is performed. ExtBuilder::default().invulnerables(vec![11]).build().execute_with(|| { - assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Balances::free_balance(&21), 2000); + assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(Balances::free_balance(21), 2000); let exposure = Staking::stakers(&21); let initial_balance = Staking::slashable_balance_of(&21); @@ -2183,9 +2183,9 @@ fn invulnerables_are_not_slashed() { ); // The validator 11 hasn't been slashed, but 21 has been. - assert_eq!(Balances::free_balance(&11), 1000); + assert_eq!(Balances::free_balance(11), 1000); // 2000 - (0.2 * initial_balance) - assert_eq!(Balances::free_balance(&21), 2000 - (2 * initial_balance / 10)); + assert_eq!(Balances::free_balance(21), 2000 - (2 * initial_balance / 10)); // ensure that nominators were slashed as well. for (initial_balance, other) in nominator_balances.into_iter().zip(exposure.others) { @@ -2203,7 +2203,7 @@ fn invulnerables_are_not_slashed() { fn dont_slash_if_fraction_is_zero() { // Don't slash if the fraction is zero. ExtBuilder::default().build().execute_with(|| { - assert_eq!(Balances::free_balance(&11), 1000); + assert_eq!(Balances::free_balance(11), 1000); on_offence_now( &[OffenceDetails { @@ -2217,7 +2217,7 @@ fn dont_slash_if_fraction_is_zero() { ); // The validator hasn't been slashed. The new era is not forced. - assert_eq!(Balances::free_balance(&11), 1000); + assert_eq!(Balances::free_balance(11), 1000); assert_ledger_consistent(11); }); } @@ -2225,7 +2225,7 @@ fn dont_slash_if_fraction_is_zero() { #[test] fn only_slash_for_max_in_era() { ExtBuilder::default().build().execute_with(|| { - assert_eq!(Balances::free_balance(&11), 1000); + assert_eq!(Balances::free_balance(11), 1000); on_offence_now( &[ @@ -2238,7 +2238,7 @@ fn only_slash_for_max_in_era() { ); // The validator has been slashed and has been force-chilled. - assert_eq!(Balances::free_balance(&11), 500); + assert_eq!(Balances::free_balance(11), 500); assert_eq!(Staking::force_era(), Forcing::ForceNew); on_offence_now( @@ -2252,7 +2252,7 @@ fn only_slash_for_max_in_era() { ); // The validator has not been slashed additionally. - assert_eq!(Balances::free_balance(&11), 500); + assert_eq!(Balances::free_balance(11), 500); on_offence_now( &[ @@ -2265,7 +2265,7 @@ fn only_slash_for_max_in_era() { ); // The validator got slashed 10% more. - assert_eq!(Balances::free_balance(&11), 400); + assert_eq!(Balances::free_balance(11), 400); assert_ledger_consistent(11); }) } @@ -2273,7 +2273,7 @@ fn only_slash_for_max_in_era() { #[test] fn garbage_collection_after_slashing() { ExtBuilder::default().existential_deposit(1).build().execute_with(|| { - assert_eq!(Balances::free_balance(&11), 256_000); + assert_eq!(Balances::free_balance(11), 256_000); on_offence_now( &[ @@ -2285,7 +2285,7 @@ fn garbage_collection_after_slashing() { &[Perbill::from_percent(10)], ); - assert_eq!(Balances::free_balance(&11), 256_000 - 25_600); + assert_eq!(Balances::free_balance(11), 256_000 - 25_600); assert!(::SlashingSpans::get(&11).is_some()); assert_eq!(::SpanSlash::get(&(11, 0)).amount_slashed(), &25_600); @@ -2302,7 +2302,7 @@ fn garbage_collection_after_slashing() { // validator and nominator slash in era are garbage-collected by era change, // so we don't test those here. - assert_eq!(Balances::free_balance(&11), 0); + assert_eq!(Balances::free_balance(11), 0); assert!(::SlashingSpans::get(&11).is_none()); assert_eq!(::SpanSlash::get(&(11, 0)).amount_slashed(), &0); }) @@ -2313,10 +2313,10 @@ fn garbage_collection_on_window_pruning() { ExtBuilder::default().build().execute_with(|| { start_era(1); - assert_eq!(Balances::free_balance(&11), 1000); + assert_eq!(Balances::free_balance(11), 1000); let exposure = Staking::stakers(&11); - assert_eq!(Balances::free_balance(&101), 2000); + assert_eq!(Balances::free_balance(101), 2000); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; on_offence_now( @@ -2331,8 +2331,8 @@ fn garbage_collection_on_window_pruning() { let now = Staking::current_era(); - assert_eq!(Balances::free_balance(&11), 900); - assert_eq!(Balances::free_balance(&101), 2000 - (nominated_value / 10)); + assert_eq!(Balances::free_balance(11), 900); + assert_eq!(Balances::free_balance(101), 2000 - (nominated_value / 10)); assert!(::ValidatorSlashInEra::get(&now, &11).is_some()); assert!(::NominatorSlashInEra::get(&now, &101).is_some()); @@ -2357,15 +2357,15 @@ fn slashing_nominators_by_span_max() { start_era(2); start_era(3); - assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Balances::free_balance(&21), 2000); - assert_eq!(Balances::free_balance(&101), 2000); + assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(Balances::free_balance(21), 2000); + assert_eq!(Balances::free_balance(101), 2000); assert_eq!(Staking::slashable_balance_of(&21), 1000); let exposure_11 = Staking::stakers(&11); let exposure_21 = Staking::stakers(&21); - assert_eq!(Balances::free_balance(&101), 2000); + assert_eq!(Balances::free_balance(101), 2000); let nominated_value_11 = exposure_11.others.iter().find(|o| o.who == 101).unwrap().value; let nominated_value_21 = exposure_21.others.iter().find(|o| o.who == 101).unwrap().value; @@ -2380,10 +2380,10 @@ fn slashing_nominators_by_span_max() { 2, ); - assert_eq!(Balances::free_balance(&11), 900); + assert_eq!(Balances::free_balance(11), 900); let slash_1_amount = Perbill::from_percent(10) * nominated_value_11; - assert_eq!(Balances::free_balance(&101), 2000 - slash_1_amount); + assert_eq!(Balances::free_balance(101), 2000 - slash_1_amount); let expected_spans = vec![ slashing::SlashingSpan { index: 1, start: 4, length: None }, @@ -2415,14 +2415,14 @@ fn slashing_nominators_by_span_max() { ); // 11 was not further slashed, but 21 and 101 were. - assert_eq!(Balances::free_balance(&11), 900); - assert_eq!(Balances::free_balance(&21), 1700); + assert_eq!(Balances::free_balance(11), 900); + assert_eq!(Balances::free_balance(21), 1700); let slash_2_amount = Perbill::from_percent(30) * nominated_value_21; assert!(slash_2_amount > slash_1_amount); // only the maximum slash in a single span is taken. - assert_eq!(Balances::free_balance(&101), 2000 - slash_2_amount); + assert_eq!(Balances::free_balance(101), 2000 - slash_2_amount); // third slash: in same era and on same validator as first, higher // in-era value, but lower slash value than slash 2. @@ -2438,15 +2438,15 @@ fn slashing_nominators_by_span_max() { ); // 11 was further slashed, but 21 and 101 were not. - assert_eq!(Balances::free_balance(&11), 800); - assert_eq!(Balances::free_balance(&21), 1700); + assert_eq!(Balances::free_balance(11), 800); + assert_eq!(Balances::free_balance(21), 1700); let slash_3_amount = Perbill::from_percent(20) * nominated_value_21; assert!(slash_3_amount < slash_2_amount); assert!(slash_3_amount > slash_1_amount); // only the maximum slash in a single span is taken. - assert_eq!(Balances::free_balance(&101), 2000 - slash_2_amount); + assert_eq!(Balances::free_balance(101), 2000 - slash_2_amount); }); } @@ -2457,7 +2457,7 @@ fn slashes_are_summed_across_spans() { start_era(2); start_era(3); - assert_eq!(Balances::free_balance(&21), 2000); + assert_eq!(Balances::free_balance(21), 2000); assert_eq!(Staking::slashable_balance_of(&21), 1000); let get_span = |account| ::SlashingSpans::get(&account).unwrap(); @@ -2478,7 +2478,7 @@ fn slashes_are_summed_across_spans() { ]; assert_eq!(get_span(21).iter().collect::>(), expected_spans); - assert_eq!(Balances::free_balance(&21), 1900); + assert_eq!(Balances::free_balance(21), 1900); // 21 has been force-chilled. re-signal intent to validate. Staking::validate(Origin::signed(20), Default::default()).unwrap(); @@ -2504,7 +2504,7 @@ fn slashes_are_summed_across_spans() { ]; assert_eq!(get_span(21).iter().collect::>(), expected_spans); - assert_eq!(Balances::free_balance(&21), 1810); + assert_eq!(Balances::free_balance(21), 1810); }); } @@ -2513,10 +2513,10 @@ fn deferred_slashes_are_deferred() { ExtBuilder::default().slash_defer_duration(2).build().execute_with(|| { start_era(1); - assert_eq!(Balances::free_balance(&11), 1000); + assert_eq!(Balances::free_balance(11), 1000); let exposure = Staking::stakers(&11); - assert_eq!(Balances::free_balance(&101), 2000); + assert_eq!(Balances::free_balance(101), 2000); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; on_offence_now( @@ -2529,25 +2529,25 @@ fn deferred_slashes_are_deferred() { &[Perbill::from_percent(10)], ); - assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Balances::free_balance(&101), 2000); + assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(Balances::free_balance(101), 2000); start_era(2); - assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Balances::free_balance(&101), 2000); + assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(Balances::free_balance(101), 2000); start_era(3); - assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Balances::free_balance(&101), 2000); + assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(Balances::free_balance(101), 2000); // at the start of era 4, slashes from era 1 are processed, // after being deferred for at least 2 full eras. start_era(4); - assert_eq!(Balances::free_balance(&11), 900); - assert_eq!(Balances::free_balance(&101), 2000 - (nominated_value / 10)); + assert_eq!(Balances::free_balance(11), 900); + assert_eq!(Balances::free_balance(101), 2000 - (nominated_value / 10)); }) } @@ -2556,10 +2556,10 @@ fn remove_deferred() { ExtBuilder::default().slash_defer_duration(2).build().execute_with(|| { start_era(1); - assert_eq!(Balances::free_balance(&11), 1000); + assert_eq!(Balances::free_balance(11), 1000); let exposure = Staking::stakers(&11); - assert_eq!(Balances::free_balance(&101), 2000); + assert_eq!(Balances::free_balance(101), 2000); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; on_offence_now( @@ -2572,8 +2572,8 @@ fn remove_deferred() { &[Perbill::from_percent(10)], ); - assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Balances::free_balance(&101), 2000); + assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(Balances::free_balance(101), 2000); start_era(2); @@ -2590,21 +2590,21 @@ fn remove_deferred() { Staking::cancel_deferred_slash(Origin::ROOT, 1, vec![0]).unwrap(); - assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Balances::free_balance(&101), 2000); + assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(Balances::free_balance(101), 2000); start_era(3); - assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Balances::free_balance(&101), 2000); + assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(Balances::free_balance(101), 2000); // at the start of era 4, slashes from era 1 are processed, // after being deferred for at least 2 full eras. start_era(4); // the first slash for 10% was cancelled, so no effect. - assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Balances::free_balance(&101), 2000); + assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(Balances::free_balance(101), 2000); start_era(5); @@ -2616,8 +2616,8 @@ fn remove_deferred() { let actual_slash = total_slash - initial_slash; // 5% slash (15 - 10) processed now. - assert_eq!(Balances::free_balance(&11), 950); - assert_eq!(Balances::free_balance(&101), 2000 - actual_slash); + assert_eq!(Balances::free_balance(11), 950); + assert_eq!(Balances::free_balance(101), 2000 - actual_slash); }) } @@ -2626,10 +2626,10 @@ fn remove_multi_deferred() { ExtBuilder::default().slash_defer_duration(2).build().execute_with(|| { start_era(1); - assert_eq!(Balances::free_balance(&11), 1000); + assert_eq!(Balances::free_balance(11), 1000); let exposure = Staking::stakers(&11); - assert_eq!(Balances::free_balance(&101), 2000); + assert_eq!(Balances::free_balance(101), 2000); on_offence_now( &[ @@ -2682,10 +2682,10 @@ fn slash_kicks_validators_not_nominators() { ExtBuilder::default().build().execute_with(|| { start_era(1); - assert_eq!(Balances::free_balance(&11), 1000); + assert_eq!(Balances::free_balance(11), 1000); let exposure = Staking::stakers(&11); - assert_eq!(Balances::free_balance(&101), 2000); + assert_eq!(Balances::free_balance(101), 2000); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; on_offence_now( @@ -2698,8 +2698,8 @@ fn slash_kicks_validators_not_nominators() { &[Perbill::from_percent(10)], ); - assert_eq!(Balances::free_balance(&11), 900); - assert_eq!(Balances::free_balance(&101), 2000 - (nominated_value / 10)); + assert_eq!(Balances::free_balance(11), 900); + assert_eq!(Balances::free_balance(101), 2000 - (nominated_value / 10)); // This is the best way to check that the validator was chilled; `get` will // return default value. @@ -2771,10 +2771,10 @@ fn zero_slash_keeps_nominators() { ExtBuilder::default().build().execute_with(|| { start_era(1); - assert_eq!(Balances::free_balance(&11), 1000); + assert_eq!(Balances::free_balance(11), 1000); let exposure = Staking::stakers(&11); - assert_eq!(Balances::free_balance(&101), 2000); + assert_eq!(Balances::free_balance(101), 2000); on_offence_now( &[ @@ -2786,8 +2786,8 @@ fn zero_slash_keeps_nominators() { &[Perbill::from_percent(0)], ); - assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Balances::free_balance(&101), 2000); + assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(Balances::free_balance(101), 2000); // This is the best way to check that the validator was chilled; `get` will // return default value. diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 0c812a02ec029..13caaedb23158 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -425,14 +425,14 @@ mod tests { .pre_dispatch(&1, CALL, info_from_weight(5), len) .is_ok() ); - assert_eq!(Balances::free_balance(&1), 100 - 5 - 5 - 10); + assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10); assert!( ChargeTransactionPayment::::from(5 /* tipped */) .pre_dispatch(&2, CALL, info_from_weight(3), len) .is_ok() ); - assert_eq!(Balances::free_balance(&2), 200 - 5 - 10 - 3 - 5); + assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 3 - 5); }); } @@ -467,7 +467,7 @@ mod tests { .execute_with(|| { // 1 ain't have a penny. - assert_eq!(Balances::free_balance(&1), 0); + assert_eq!(Balances::free_balance(1), 0); let len = 100; @@ -514,7 +514,7 @@ mod tests { .pre_dispatch(&1, CALL, info_from_weight(3), len) .is_ok() ); - assert_eq!(Balances::free_balance(&1), 100 - 10 - 5 - (10 + 3) * 3 / 2); + assert_eq!(Balances::free_balance(1), 100 - 10 - 5 - (10 + 3) * 3 / 2); }) } diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index 2ce7a6362f7fc..76488d3d7aa59 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -849,8 +849,8 @@ mod tests { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_ok!(Treasury::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3)); - assert_eq!(Balances::reserved_balance(&0), 12); - assert_eq!(Balances::free_balance(&0), 88); + assert_eq!(Balances::reserved_balance(0), 12); + assert_eq!(Balances::free_balance(0), 88); // other reports don't count. assert_noop!( @@ -865,9 +865,9 @@ mod tests { assert_noop!(Treasury::tip(Origin::signed(9), h.clone(), 10), BadOrigin); System::set_block_number(2); assert_ok!(Treasury::close_tip(Origin::signed(100), h.into())); - assert_eq!(Balances::reserved_balance(&0), 0); - assert_eq!(Balances::free_balance(&0), 102); - assert_eq!(Balances::free_balance(&3), 8); + assert_eq!(Balances::reserved_balance(0), 0); + assert_eq!(Balances::free_balance(0), 102); + assert_eq!(Balances::free_balance(3), 8); }); } @@ -876,16 +876,16 @@ mod tests { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_ok!(Treasury::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 0)); - assert_eq!(Balances::reserved_balance(&0), 12); - assert_eq!(Balances::free_balance(&0), 88); + assert_eq!(Balances::reserved_balance(0), 12); + assert_eq!(Balances::free_balance(0), 88); let h = BlakeTwo256::hash_of(&(BlakeTwo256::hash(b"awesome.dot"), 0u64)); assert_ok!(Treasury::tip(Origin::signed(10), h.clone(), 10)); assert_ok!(Treasury::tip(Origin::signed(11), h.clone(), 10)); assert_ok!(Treasury::tip(Origin::signed(12), h.clone(), 10)); System::set_block_number(2); assert_ok!(Treasury::close_tip(Origin::signed(100), h.into())); - assert_eq!(Balances::reserved_balance(&0), 0); - assert_eq!(Balances::free_balance(&0), 110); + assert_eq!(Balances::reserved_balance(0), 0); + assert_eq!(Balances::free_balance(0), 110); }); } @@ -906,7 +906,7 @@ mod tests { System::set_block_number(2); assert_noop!(Treasury::close_tip(Origin::NONE, h.into()), BadOrigin); assert_ok!(Treasury::close_tip(Origin::signed(0), h.into())); - assert_eq!(Balances::free_balance(&3), 10); + assert_eq!(Balances::free_balance(3), 10); assert_noop!(Treasury::close_tip(Origin::signed(100), h.into()), Error::::UnknownTip); }); @@ -938,7 +938,7 @@ mod tests { assert_ok!(Treasury::tip(Origin::signed(12), h.clone(), 1000000)); System::set_block_number(2); assert_ok!(Treasury::close_tip(Origin::signed(0), h.into())); - assert_eq!(Balances::free_balance(&3), 10); + assert_eq!(Balances::free_balance(3), 10); }); } @@ -957,7 +957,7 @@ mod tests { assert_ok!(Treasury::tip(Origin::signed(10), h.clone(), 10)); System::set_block_number(2); assert_ok!(Treasury::close_tip(Origin::signed(0), h.into())); - assert_eq!(Balances::free_balance(&3), 10); + assert_eq!(Balances::free_balance(3), 10); }); } @@ -974,8 +974,8 @@ mod tests { fn spend_proposal_takes_min_deposit() { new_test_ext().execute_with(|| { assert_ok!(Treasury::propose_spend(Origin::signed(0), 1, 3)); - assert_eq!(Balances::free_balance(&0), 99); - assert_eq!(Balances::reserved_balance(&0), 1); + assert_eq!(Balances::free_balance(0), 99); + assert_eq!(Balances::reserved_balance(0), 1); }); } @@ -983,8 +983,8 @@ mod tests { fn spend_proposal_takes_proportional_deposit() { new_test_ext().execute_with(|| { assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_eq!(Balances::free_balance(&0), 95); - assert_eq!(Balances::reserved_balance(&0), 5); + assert_eq!(Balances::free_balance(0), 95); + assert_eq!(Balances::reserved_balance(0), 5); }); } @@ -1007,7 +1007,7 @@ mod tests { assert_ok!(Treasury::approve_proposal(Origin::ROOT, 0)); >::on_finalize(1); - assert_eq!(Balances::free_balance(&3), 0); + assert_eq!(Balances::free_balance(3), 0); assert_eq!(Treasury::pot(), 100); }); } @@ -1034,7 +1034,7 @@ mod tests { assert_ok!(Treasury::reject_proposal(Origin::ROOT, 0)); >::on_finalize(2); - assert_eq!(Balances::free_balance(&3), 0); + assert_eq!(Balances::free_balance(3), 0); assert_eq!(Treasury::pot(), 50); }); } @@ -1085,7 +1085,7 @@ mod tests { assert_ok!(Treasury::approve_proposal(Origin::ROOT, 0)); >::on_finalize(2); - assert_eq!(Balances::free_balance(&3), 100); + assert_eq!(Balances::free_balance(3), 100); assert_eq!(Treasury::pot(), 0); }); } @@ -1104,7 +1104,7 @@ mod tests { let _ = Balances::deposit_into_existing(&Treasury::account_id(), 100).unwrap(); >::on_finalize(4); - assert_eq!(Balances::free_balance(&3), 150); // Fund has been spent + assert_eq!(Balances::free_balance(3), 150); // Fund has been spent assert_eq!(Treasury::pot(), 25); // Pot has finally changed }); } @@ -1129,7 +1129,7 @@ mod tests { >::on_finalize(4); assert_eq!(Treasury::pot(), 0); // Pot is emptied - assert_eq!(Balances::free_balance(&Treasury::account_id()), 1); // but the account is still there + assert_eq!(Balances::free_balance(Treasury::account_id()), 1); // but the account is still there }); } @@ -1145,7 +1145,7 @@ mod tests { let mut t: sp_io::TestExternalities = t.into(); t.execute_with(|| { - assert_eq!(Balances::free_balance(&Treasury::account_id()), 0); // Account does not exist + assert_eq!(Balances::free_balance(Treasury::account_id()), 0); // Account does not exist assert_eq!(Treasury::pot(), 0); // Pot is empty assert_ok!(Treasury::propose_spend(Origin::signed(0), 99, 3)); @@ -1154,16 +1154,16 @@ mod tests { assert_ok!(Treasury::approve_proposal(Origin::ROOT, 1)); >::on_finalize(2); assert_eq!(Treasury::pot(), 0); // Pot hasn't changed - assert_eq!(Balances::free_balance(&3), 0); // Balance of `3` hasn't changed + assert_eq!(Balances::free_balance(3), 0); // Balance of `3` hasn't changed Balances::make_free_balance_be(&Treasury::account_id(), 100); assert_eq!(Treasury::pot(), 99); // Pot now contains funds - assert_eq!(Balances::free_balance(&Treasury::account_id()), 100); // Account does exist + assert_eq!(Balances::free_balance(Treasury::account_id()), 100); // Account does exist >::on_finalize(4); assert_eq!(Treasury::pot(), 0); // Pot has changed - assert_eq!(Balances::free_balance(&3), 99); // Balance of `3` has changed + assert_eq!(Balances::free_balance(3), 99); // Balance of `3` has changed }); } } diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index a8269d934d54f..fcd340eef5557 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -765,12 +765,12 @@ mod tests { let call = Box::new(Call::Balances(BalancesCall::transfer(6, 15))); assert_ok!(Utility::as_multi(Origin::signed(1), 2, vec![2, 3], None, call.clone())); - assert_eq!(Balances::free_balance(&1), 2); - assert_eq!(Balances::reserved_balance(&1), 3); + assert_eq!(Balances::free_balance(1), 2); + assert_eq!(Balances::reserved_balance(1), 3); assert_ok!(Utility::as_multi(Origin::signed(2), 2, vec![1, 3], Some(now()), call)); - assert_eq!(Balances::free_balance(&1), 5); - assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Balances::free_balance(1), 5); + assert_eq!(Balances::reserved_balance(1), 0); }); } @@ -781,13 +781,13 @@ mod tests { let hash = call.using_encoded(blake2_256); assert_ok!(Utility::approve_as_multi(Origin::signed(1), 3, vec![2, 3], None, hash.clone())); assert_ok!(Utility::approve_as_multi(Origin::signed(2), 3, vec![1, 3], Some(now()), hash.clone())); - assert_eq!(Balances::free_balance(&1), 6); - assert_eq!(Balances::reserved_balance(&1), 4); + assert_eq!(Balances::free_balance(1), 6); + assert_eq!(Balances::reserved_balance(1), 4); assert_ok!( Utility::cancel_as_multi(Origin::signed(1), 3, vec![2, 3], now(), hash.clone()), ); - assert_eq!(Balances::free_balance(&1), 10); - assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Balances::free_balance(1), 10); + assert_eq!(Balances::reserved_balance(1), 0); }); } @@ -832,10 +832,10 @@ mod tests { let call = Box::new(Call::Balances(BalancesCall::transfer(6, 15))); let hash = call.using_encoded(blake2_256); assert_ok!(Utility::approve_as_multi(Origin::signed(1), 2, vec![2, 3], None, hash)); - assert_eq!(Balances::free_balance(&6), 0); + assert_eq!(Balances::free_balance(6), 0); assert_ok!(Utility::as_multi(Origin::signed(2), 2, vec![1, 3], Some(now()), call)); - assert_eq!(Balances::free_balance(&6), 15); + assert_eq!(Balances::free_balance(6), 15); }); } @@ -851,10 +851,10 @@ mod tests { let hash = call.using_encoded(blake2_256); assert_ok!(Utility::approve_as_multi(Origin::signed(1), 3, vec![2, 3], None, hash.clone())); assert_ok!(Utility::approve_as_multi(Origin::signed(2), 3, vec![1, 3], Some(now()), hash.clone())); - assert_eq!(Balances::free_balance(&6), 0); + assert_eq!(Balances::free_balance(6), 0); assert_ok!(Utility::as_multi(Origin::signed(3), 3, vec![1, 2], Some(now()), call)); - assert_eq!(Balances::free_balance(&6), 15); + assert_eq!(Balances::free_balance(6), 15); }); } @@ -885,10 +885,10 @@ mod tests { let call = Box::new(Call::Balances(BalancesCall::transfer(6, 15))); assert_ok!(Utility::as_multi(Origin::signed(1), 2, vec![2, 3], None, call.clone())); - assert_eq!(Balances::free_balance(&6), 0); + assert_eq!(Balances::free_balance(6), 0); assert_ok!(Utility::as_multi(Origin::signed(2), 2, vec![1, 3], Some(now()), call)); - assert_eq!(Balances::free_balance(&6), 15); + assert_eq!(Balances::free_balance(6), 15); }); } @@ -908,8 +908,8 @@ mod tests { assert_ok!(Utility::as_multi(Origin::signed(3), 2, vec![1, 2], Some(now()), call2)); assert_ok!(Utility::as_multi(Origin::signed(3), 2, vec![1, 2], Some(now()), call1)); - assert_eq!(Balances::free_balance(&6), 10); - assert_eq!(Balances::free_balance(&7), 5); + assert_eq!(Balances::free_balance(6), 10); + assert_eq!(Balances::free_balance(7), 5); }); } @@ -924,7 +924,7 @@ mod tests { let call = Box::new(Call::Balances(BalancesCall::transfer(6, 10))); assert_ok!(Utility::as_multi(Origin::signed(1), 2, vec![2, 3], None, call.clone())); assert_ok!(Utility::as_multi(Origin::signed(2), 2, vec![1, 3], Some(now()), call.clone())); - assert_eq!(Balances::free_balance(&multi), 5); + assert_eq!(Balances::free_balance(multi), 5); assert_ok!(Utility::as_multi(Origin::signed(1), 2, vec![2, 3], None, call.clone())); assert_ok!(Utility::as_multi(Origin::signed(3), 2, vec![1, 2], Some(now()), call)); @@ -994,7 +994,7 @@ mod tests { ); assert_ok!(Utility::as_multi(Origin::signed(1), 1, vec![2, 3], None, call)); - assert_eq!(Balances::free_balance(&6), 15); + assert_eq!(Balances::free_balance(6), 15); }); } @@ -1013,46 +1013,46 @@ mod tests { 0, Box::new(Call::Balances(BalancesCall::transfer(2, 3))), )); - assert_eq!(Balances::free_balance(&sub_1_0), 2); - assert_eq!(Balances::free_balance(&2), 13); + assert_eq!(Balances::free_balance(sub_1_0), 2); + assert_eq!(Balances::free_balance(2), 13); }); } #[test] fn batch_with_root_works() { new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(&1), 10); - assert_eq!(Balances::free_balance(&2), 10); + assert_eq!(Balances::free_balance(1), 10); + assert_eq!(Balances::free_balance(2), 10); assert_ok!(Utility::batch(Origin::ROOT, vec![ Call::Balances(BalancesCall::force_transfer(1, 2, 5)), Call::Balances(BalancesCall::force_transfer(1, 2, 5)) ])); - assert_eq!(Balances::free_balance(&1), 0); - assert_eq!(Balances::free_balance(&2), 20); + assert_eq!(Balances::free_balance(1), 0); + assert_eq!(Balances::free_balance(2), 20); }); } #[test] fn batch_with_signed_works() { new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(&1), 10); - assert_eq!(Balances::free_balance(&2), 10); + assert_eq!(Balances::free_balance(1), 10); + assert_eq!(Balances::free_balance(2), 10); assert_ok!( Utility::batch(Origin::signed(1), vec![ Call::Balances(BalancesCall::transfer(2, 5)), Call::Balances(BalancesCall::transfer(2, 5)) ]), ); - assert_eq!(Balances::free_balance(&1), 0); - assert_eq!(Balances::free_balance(&2), 20); + assert_eq!(Balances::free_balance(1), 0); + assert_eq!(Balances::free_balance(2), 20); }); } #[test] fn batch_early_exit_works() { new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(&1), 10); - assert_eq!(Balances::free_balance(&2), 10); + assert_eq!(Balances::free_balance(1), 10); + assert_eq!(Balances::free_balance(2), 10); assert_ok!( Utility::batch(Origin::signed(1), vec![ Call::Balances(BalancesCall::transfer(2, 5)), @@ -1060,8 +1060,8 @@ mod tests { Call::Balances(BalancesCall::transfer(2, 5)), ]), ); - assert_eq!(Balances::free_balance(&1), 5); - assert_eq!(Balances::free_balance(&2), 15); + assert_eq!(Balances::free_balance(1), 5); + assert_eq!(Balances::free_balance(2), 15); }); } } diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 10069c9905981..ae0fca1c61aec 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -431,7 +431,7 @@ mod tests { s.top = data.into_iter().collect(); sp_io::TestExternalities::new(s).execute_with(|| { Balances::on_initialize(1); - assert_eq!(Balances::free_balance(&6), 60); + assert_eq!(Balances::free_balance(6), 60); assert_eq!(Balances::usable_balance(&6), 30); System::set_block_number(2); assert_ok!(Vesting::vest(Origin::signed(6))); From b60ac8a3912b320992ab577684df1fd721730e13 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 29 Jan 2020 12:42:48 +0100 Subject: [PATCH 28/29] Bump runtime version --- bin/node/runtime/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 613f156c923fc..fb7f751da7ca2 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -80,8 +80,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 207, - impl_version: 208, + spec_version: 209, + impl_version: 0, apis: RUNTIME_API_VERSIONS, }; From 735b31f330ebdc5e76e52376f5aa05b8452aa6ea Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 29 Jan 2020 14:02:14 +0100 Subject: [PATCH 29/29] Fixes --- frame/democracy/src/lib.rs | 2 +- frame/vesting/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 8d0400592abdc..da0cccb1d0e6b 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -307,7 +307,7 @@ decl_storage! { /// Accounts for which there are locks in action which may be removed at some point in the /// future. The value is the block number at which the lock expires and may be removed. - pub Locks get(locks): map T::AccountId => Option; + pub Locks get(locks): map hasher(blake2_256) T::AccountId => Option; /// True if the last referendum tabled was submitted externally. False if it was a public /// proposal. diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index ae0fca1c61aec..4a079e7693b49 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -110,7 +110,7 @@ decl_storage! { trait Store for Module as Vesting { /// Information regarding the vesting of a given account. pub Vesting get(fn vesting): - map T::AccountId => Option, T::BlockNumber>>; + map hasher(blake2_256) T::AccountId => Option, T::BlockNumber>>; } add_extra_genesis { config(vesting): Vec<(T::AccountId, T::BlockNumber, T::BlockNumber, BalanceOf)>;