Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Lazy reaping #4895

Merged
merged 24 commits into from
Feb 24, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bin/node/cli/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ pub fn testnet_genesis(
}),
pallet_session: Some(SessionConfig {
keys: initial_authorities.iter().map(|x| {
(x.0.clone(), session_keys(x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone()))
(x.0.clone(), x.0.clone(), session_keys(x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone()))
}).collect::<Vec<_>>(),
}),
pallet_staking: Some(StakingConfig {
Expand Down
10 changes: 5 additions & 5 deletions bin/node/executor/tests/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ fn panic_execution_with_foreign_code_gives_error() {
let mut t = TestExternalities::<Blake2Hasher>::new_with_code(BLOATY_CODE, Storage {
top: map![
<frame_system::Account<Runtime>>::hashed_key_for(alice()) => {
(69u128, 0u128, 0u128, 0u128).encode()
(69u128, 0u8, 0u128, 0u128, 0u128).encode()
},
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec() => {
69_u128.encode()
Expand Down Expand Up @@ -200,7 +200,7 @@ fn bad_extrinsic_with_native_equivalent_code_gives_error() {
let mut t = TestExternalities::<Blake2Hasher>::new_with_code(COMPACT_CODE, Storage {
top: map![
<frame_system::Account<Runtime>>::hashed_key_for(alice()) => {
(0u32, 69u128, 0u128, 0u128, 0u128).encode()
(0u32, 0u8, 69u128, 0u128, 0u128, 0u128).encode()
},
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec() => {
69_u128.encode()
Expand Down Expand Up @@ -236,7 +236,7 @@ fn successful_execution_with_native_equivalent_code_gives_ok() {
let mut t = TestExternalities::<Blake2Hasher>::new_with_code(COMPACT_CODE, Storage {
top: map![
<frame_system::Account<Runtime>>::hashed_key_for(alice()) => {
(0u32, 111 * DOLLARS, 0u128, 0u128, 0u128).encode()
(0u32, 0u8, 111 * DOLLARS, 0u128, 0u128, 0u128).encode()
},
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec() => {
(111 * DOLLARS).encode()
Expand Down Expand Up @@ -278,7 +278,7 @@ fn successful_execution_with_foreign_code_gives_ok() {
let mut t = TestExternalities::<Blake2Hasher>::new_with_code(BLOATY_CODE, Storage {
top: map![
<frame_system::Account<Runtime>>::hashed_key_for(alice()) => {
(0u32, 111 * DOLLARS, 0u128, 0u128, 0u128).encode()
(0u32, 0u8, 111 * DOLLARS, 0u128, 0u128, 0u128).encode()
},
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec() => {
(111 * DOLLARS).encode()
Expand Down Expand Up @@ -733,7 +733,7 @@ fn successful_execution_gives_ok() {
let mut t = TestExternalities::<Blake2Hasher>::new_with_code(COMPACT_CODE, Storage {
top: map![
<frame_system::Account<Runtime>>::hashed_key_for(alice()) => {
(0u32, 111 * DOLLARS, 0u128, 0u128, 0u128).encode()
(0u32, 0u8, 111 * DOLLARS, 0u128, 0u128, 0u128).encode()
},
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec() => {
(111 * DOLLARS).encode()
Expand Down
4 changes: 2 additions & 2 deletions bin/node/executor/tests/fees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,10 @@ fn transaction_fee_is_correct_ultimate() {
let mut t = TestExternalities::<Blake2Hasher>::new_with_code(COMPACT_CODE, Storage {
top: map![
<frame_system::Account<Runtime>>::hashed_key_for(alice()) => {
(0u32, 100 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS).encode()
(0u32, 0u8, 100 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS).encode()
},
<frame_system::Account<Runtime>>::hashed_key_for(bob()) => {
(0u32, 10 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS).encode()
(0u32, 0u8, 10 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS).encode()
},
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec() => {
(110 * DOLLARS).encode()
Expand Down
5 changes: 3 additions & 2 deletions bin/node/executor/tests/submit_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,9 @@ fn submitted_transaction_should_be_valid() {
// add balance to the account
let author = extrinsic.signature.clone().unwrap().0;
let address = Indices::lookup(author).unwrap();
let account = pallet_balances::AccountData { free: 5_000_000_000_000, ..Default::default() };
<frame_system::Account<Runtime>>::insert(&address, (0u32, account));
let data = pallet_balances::AccountData { free: 5_000_000_000_000, ..Default::default() };
let account = frame_system::AccountInfo { nonce: 0u32, refcount: 0u8, data };
<frame_system::Account<Runtime>>::insert(&address, account);

// check validity
let res = Executive::validate_transaction(extrinsic);
Expand Down
2 changes: 1 addition & 1 deletion bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ impl frame_system::Trait for Runtime {
type ModuleToIndex = ModuleToIndex;
type AccountData = pallet_balances::AccountData<Balance>;
type OnNewAccount = ();
type OnReapAccount = (Balances, Staking, Contracts, Session, Recovery);
type OnReapAccount = ();
shawntabrizi marked this conversation as resolved.
Show resolved Hide resolved
}

parameter_types! {
Expand Down
6 changes: 3 additions & 3 deletions bin/node/testing/src/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,15 @@ pub fn config_endowed(
}),
pallet_session: Some(SessionConfig {
keys: vec![
(alice(), to_session_keys(
(dave(), alice(), to_session_keys(
&Ed25519Keyring::Alice,
&Sr25519Keyring::Alice,
)),
(bob(), to_session_keys(
(eve(), bob(), to_session_keys(
&Ed25519Keyring::Bob,
&Sr25519Keyring::Bob,
)),
(charlie(), to_session_keys(
(ferdie(), charlie(), to_session_keys(
&Ed25519Keyring::Charlie,
&Sr25519Keyring::Charlie,
)),
Expand Down
1 change: 0 additions & 1 deletion frame/balances/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ frame-support = { version = "2.0.0", default-features = false, path = "../suppor
frame-system = { version = "2.0.0", default-features = false, path = "../system" }

[dev-dependencies]
sp-io = { version = "2.0.0", path = "../../primitives/io" }
sp-core = { version = "2.0.0", path = "../../primitives/core" }
pallet-transaction-payment = { version = "2.0.0", path = "../transaction-payment" }

Expand Down
46 changes: 37 additions & 9 deletions frame/balances/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ mod benchmarking;

use sp_std::prelude::*;
use sp_std::{cmp, result, mem, fmt::Debug, ops::BitOr, convert::Infallible};
use sp_io::hashing::twox_64;
use codec::{Codec, Encode, Decode};
use frame_support::{
StorageValue, Parameter, decl_event, decl_storage, decl_module, decl_error, ensure,
Expand All @@ -178,7 +179,7 @@ use sp_runtime::{
};
use frame_system::{self as system, ensure_signed, ensure_root};
use frame_support::storage::migration::{
get_storage_value, take_storage_value, put_storage_value, StorageIterator
get_storage_value, take_storage_value, put_storage_value, StorageIterator, have_storage_value
};

pub use self::imbalances::{PositiveImbalance, NegativeImbalance};
Expand Down Expand Up @@ -609,7 +610,16 @@ impl<T: Trait<I>, I: Instance> Module<T, I> {

for (hash, balances) in StorageIterator::<AccountData<T::Balance>>::new(b"Balances", b"Account").drain() {
let nonce = take_storage_value::<T::Index>(b"System", b"AccountNonce", &hash).unwrap_or_default();
put_storage_value(b"System", b"Account", &hash, (nonce, balances));
let mut refs: system::RefCount = 0;
// The items in Kusama that would result in a ref count being incremented.
if have_storage_value(b"Democracy", b"Proxy", &hash) { refs += 1 }
// We skip Recovered since it's being replaced anyway.
let mut prefixed_hash = twox_64(&b":session:keys"[..]).to_vec();
prefixed_hash.extend(&b":session:keys"[..]);
prefixed_hash.extend(&hash[..]);
if have_storage_value(b"Session", b"NextKeys", &prefixed_hash) { refs += 1 }
if have_storage_value(b"Staking", b"Bonded", &hash) { refs += 1 }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that we don't have an easy and better choice here, but maybe we should document the rules of these references somewhere in a very strict way. The pattern in staking/session of inc_ref/dec_red reminds me of malloc/free and such, paradigms that we probably want to avoid.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these the kind of rules would you be looking for?

If a module wants to "keep alive" an account until it is done with it, it should put a reference counter on it.

When it is done with it, it should remove that reference counter.

It should only happen once each way. (But I guess there is nothing that would stop a module from managing multiple reference counters in both directions.)

put_storage_value(b"System", b"Account", &hash, (nonce, refs, &balances));
}
}

Expand Down Expand Up @@ -721,14 +731,20 @@ impl<T: Trait<I>, I: Instance> Module<T, I> {
}
}
});
Locks::<T, I>::insert(who, locks);
}
}

impl<T: Trait<I>, I: Instance> OnReapAccount<T::AccountId> for Module<T, I> {
fn on_reap_account(who: &T::AccountId) {
Locks::<T, I>::remove(who);
Account::<T, I>::remove(who);
let existed = Locks::<T, I>::contains_key(who);
if locks.is_empty() {
Locks::<T, I>::remove(who);
if existed {
// TODO: use Locks::<T, I>::hashed_key
gavofyork marked this conversation as resolved.
Show resolved Hide resolved
system::Module::<T>::dec_ref(who);
}
} else {
Locks::<T, I>::insert(who, locks);
if !existed {
system::Module::<T>::inc_ref(who);
}
}
}
}

Expand Down Expand Up @@ -1040,6 +1056,7 @@ impl<T: Trait<I>, I: Instance> Currency<T::AccountId> for Module<T, I> where
)?;

let allow_death = existence_requirement == ExistenceRequirement::AllowDeath;
let allow_death = allow_death && system::Module::<T>::allow_death(transactor);
ensure!(allow_death || from_account.free >= ed, Error::<T, I>::KeepAlive);

Ok(())
Expand Down Expand Up @@ -1283,6 +1300,17 @@ impl<T: Trait<I>, I: Instance> ReservableCurrency<T::AccountId> for Module<T, I>
}
}

/// Implement `OnReapAccount` to remove the local account, if using local account storage.
///
/// NOTE: You probably won't need to use this! This only needs to be "wired in" to System module
/// if you're using the local balance storage. **If you're using the composite system account
/// storage (which is the default in most examples and tests) then there's no need.**
impl<T: Trait<I>, I: Instance> OnReapAccount<T::AccountId> for Module<T, I> {
shawntabrizi marked this conversation as resolved.
Show resolved Hide resolved
fn on_reap_account(who: &T::AccountId) {
Account::<T, I>::remove(who);
}
}

impl<T: Trait<I>, I: Instance> LockableCurrency<T::AccountId> for Module<T, I>
where
T::Balance: MaybeSerializeDeserialize + Debug
Expand Down
15 changes: 13 additions & 2 deletions frame/balances/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ macro_rules! decl_tests {
use sp_runtime::{Fixed64, traits::{SignedExtension, BadOrigin}};
use frame_support::{
assert_noop, assert_ok, assert_err,
traits::{LockableCurrency, LockIdentifier, WithdrawReason, WithdrawReasons,
Currency, ReservableCurrency, ExistenceRequirement::AllowDeath}
traits::{
LockableCurrency, LockIdentifier, WithdrawReason, WithdrawReasons,
Currency, ReservableCurrency, ExistenceRequirement::AllowDeath, StoredMap
}
};
use pallet_transaction_payment::ChargeTransactionPayment;
use frame_system::RawOrigin;
Expand Down Expand Up @@ -55,6 +57,15 @@ macro_rules! decl_tests {
});
}

#[test]
fn account_should_be_reaped() {
<$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| {
assert_eq!(Balances::free_balance(1), 10);
assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 10, AllowDeath));
assert!(!<<Test as Trait>::AccountStore as StoredMap<u64, AccountData<u64>>>::is_explicit(&1));
});
}

#[test]
fn partial_locking_should_work() {
<$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| {
Expand Down
2 changes: 1 addition & 1 deletion frame/balances/src/tests_composite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl frame_system::Trait for Test {
type ModuleToIndex = ();
type AccountData = super::AccountData<u64>;
type OnNewAccount = ();
type OnReapAccount = Module<Test>;
type OnReapAccount = ();
}
parameter_types! {
pub const TransactionBaseFee: u64 = 0;
Expand Down
3 changes: 3 additions & 0 deletions frame/contracts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -941,6 +941,9 @@ decl_storage! {
}
}

// TODO: this should be removed in favour of a self-destruct contract host function allowing the
// contract to delete all storage and the `ContractInfoOf` key and transfer remaining balance to
// some other account. As it stands, it's an economic insecurity on any smart-contract chain.
gavofyork marked this conversation as resolved.
Show resolved Hide resolved
impl<T: Trait> OnReapAccount<T::AccountId> for Module<T> {
fn on_reap_account(who: &T::AccountId) {
if let Some(ContractInfo::Alive(info)) = <ContractInfoOf<T>>::take(who) {
Expand Down
Loading