Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 15 additions & 0 deletions prdoc/pr_11649.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
title: 'Consolidate try-state warnings into summary counts'
doc:
- audience: Runtime Dev
description: |-
Aggregates repetitive try-state warnings (min bond violations, pool ED imbalance, depositor
insufficient stake) into single summary lines with counts and up to 10 example accounts.
Reduces log noise from hundreds of expected per-item warnings on production runtimes.

Closes #11646.

crates:
- name: pallet-staking-async
bump: patch
- name: pallet-nomination-pools
bump: patch
46 changes: 43 additions & 3 deletions substrate/frame/nomination-pools/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4008,7 +4008,13 @@ impl<T: Config> Pallet<T> {
})?;

let mut expected_tvl: BalanceOf<T> = Default::default();
let mut depositor_undermin: Vec<(PoolId, T::AccountId)> = Vec::new();
let mut depositor_undermin_total: u32 = 0;
let mut total_pools: u32 = 0;
const MAX_EXAMPLES: usize = 10;

BondedPools::<T>::iter().try_for_each(|(id, inner)| -> Result<(), TryRuntimeError> {
total_pools += 1;
Copy link
Copy Markdown
Contributor

@andreitrand andreitrand Apr 7, 2026

Choose a reason for hiding this comment

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

Nit: total_pools simply equals BondedPools::<T>::count(), so I suggest simply setting it to this value before the iteration rather than incrementing it by 1 (for extra clarity).

let bonded_pool = BondedPool { id, inner };
ensure!(
pools_members.get(&id).copied().unwrap_or_default() ==
Expand All @@ -4026,8 +4032,12 @@ impl<T: Config> Pallet<T> {
.is_destroying_and_only_depositor(depositor.active_points()) ||
depositor.active_points() >= MinCreateBond::<T>::get();
if !depositor_has_enough_stake {
depositor_undermin_total += 1;
Comment thread
Ank4n marked this conversation as resolved.
if depositor_undermin.len() < MAX_EXAMPLES {
depositor_undermin.push((id, bonded_pool.roles.depositor.clone()));
}
log!(
warn,
trace,
"pool {:?} has depositor {:?} with insufficient stake {:?}, minimum required is {:?}",
id,
bonded_pool.roles.depositor,
Expand All @@ -4046,6 +4056,17 @@ impl<T: Config> Pallet<T> {
Ok(())
})?;

if depositor_undermin_total > 0 {
log!(
warn,
"{}/{} pools have depositor with insufficient stake, minimum required is {:?}. Examples: {:?}",
depositor_undermin_total,
total_pools,
MinCreateBond::<T>::get(),
depositor_undermin,
);
}

ensure!(
MaxPoolMembers::<T>::get().map_or(true, |max| all_members <= max),
Error::<T>::MaxPoolMembers
Expand Down Expand Up @@ -4108,17 +4129,25 @@ impl<T: Config> Pallet<T> {
debug_assertions
))]
pub fn check_ed_imbalance() -> Result<u32, DispatchError> {
let mut needs_adjust = 0;
let mut needs_adjust: u32 = 0;
let mut total_pools: u32 = 0;
let mut ed_examples: Vec<PoolId> = Vec::new();
const MAX_EXAMPLES: usize = 10;

BondedPools::<T>::iter_keys().for_each(|id| {
total_pools += 1;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: Same as above: I suggest setting total_pools directly to BondedPools::<T>::count() before the loop.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No strong opinions but I don't think it matters much. We are looping anyways.

let reward_acc = Self::generate_reward_account(id);
let frozen_balance =
T::Currency::balance_frozen(&FreezeReason::PoolMinBalance.into(), &reward_acc);

let expected_frozen_balance = T::Currency::minimum_balance();
if frozen_balance != expected_frozen_balance {
needs_adjust += 1;
if ed_examples.len() < MAX_EXAMPLES {
ed_examples.push(id);
}
log!(
warn,
trace,
"pool {:?} has incorrect ED frozen that can result from change in ED. Expected = {:?}, Actual = {:?}. Use `adjust_pool_deposit` to fix it",
id,
expected_frozen_balance,
Expand All @@ -4127,6 +4156,17 @@ impl<T: Config> Pallet<T> {
}
});

if needs_adjust > 0 {
log!(
warn,
"{}/{} pools have incorrect ED frozen (expected {:?}). Use `adjust_pool_deposit` to fix. Examples: {:?}",
needs_adjust,
total_pools,
T::Currency::minimum_balance(),
ed_examples,
);
}

Ok(needs_adjust)
}
/// Fully unbond the shares of `member`, when executed from `origin`.
Expand Down
82 changes: 77 additions & 5 deletions substrate/frame/staking-async/src/pallet/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1945,8 +1945,17 @@ impl<T: Config> Pallet<T> {
/// * For virtual stakers, locked funds should be zero and payee should be non-stash account.
/// * Staking ledger and bond are not corrupted.
fn check_ledgers() -> Result<(), TryRuntimeError> {
let mut chilled_undermin: Vec<T::AccountId> = Vec::new();
let mut chilled_total: u32 = 0;
let mut nominator_undermin: Vec<T::AccountId> = Vec::new();
let mut nominator_total: u32 = 0;
let mut validator_undermin: Vec<T::AccountId> = Vec::new();
let mut validator_total: u32 = 0;
let mut total_ledgers: u32 = 0;

Bonded::<T>::iter()
.map(|(stash, ctrl)| {
total_ledgers += 1;
// ensure locks consistency.
if VirtualStakers::<T>::contains_key(stash.clone()) {
ensure!(
Expand Down Expand Up @@ -1990,10 +1999,50 @@ impl<T: Config> Pallet<T> {
}

Self::ensure_ledger_consistent(&ctrl)?;
Self::ensure_ledger_role_and_min_bond(&ctrl)?;
Self::collect_min_bond_violations(
&ctrl,
&mut chilled_undermin,
&mut chilled_total,
&mut nominator_undermin,
&mut nominator_total,
&mut validator_undermin,
&mut validator_total,
)?;
Ok(())
})
.collect::<Result<Vec<_>, _>>()?;

if chilled_total > 0 {
log!(
warn,
"{} chilled stashes (out of {} total ledgers) have less stake than minimum role bond ({:?}). Examples: {:?}",
chilled_total,
total_ledgers,
Comment thread
Ank4n marked this conversation as resolved.
Self::min_chilled_bond(),
chilled_undermin,
);
}
if nominator_total > 0 {
log!(
warn,
"{} nominators (out of {} total ledgers) have less stake than minimum role bond ({:?}). Examples: {:?}",
nominator_total,
total_ledgers,
Self::min_nominator_bond(),
nominator_undermin,
);
}
if validator_total > 0 {
log!(
warn,
"{} validators (out of {} total ledgers) have less stake than minimum role bond ({:?}). Examples: {:?}",
validator_total,
total_ledgers,
Self::min_validator_bond(),
validator_undermin,
);
}

Ok(())
}

Expand Down Expand Up @@ -2135,7 +2184,18 @@ impl<T: Config> Pallet<T> {
Ok(())
}

fn ensure_ledger_role_and_min_bond(ctrl: &T::AccountId) -> Result<(), TryRuntimeError> {
/// Checks if a ledger's stash has less stake than the minimum for its role and collects
/// violations into the provided accumulators (up to `MAX_EXAMPLES` examples per role).
fn collect_min_bond_violations(
ctrl: &T::AccountId,
chilled_undermin: &mut Vec<T::AccountId>,
chilled_total: &mut u32,
nominator_undermin: &mut Vec<T::AccountId>,
nominator_total: &mut u32,
validator_undermin: &mut Vec<T::AccountId>,
validator_total: &mut u32,
) -> Result<(), TryRuntimeError> {
const MAX_EXAMPLES: usize = 10;
let ledger = Self::ledger(StakingAccount::Controller(ctrl.clone()))?;
let stash = ledger.stash;

Expand All @@ -2146,8 +2206,12 @@ impl<T: Config> Pallet<T> {
(false, false) => {
if ledger.active < Self::min_chilled_bond() && !ledger.active.is_zero() {
// chilled accounts allow to go to zero and fully unbond ^^^^^^^^^
*chilled_total += 1;
if chilled_undermin.len() < MAX_EXAMPLES {
chilled_undermin.push(stash.clone());
}
log!(
warn,
trace,
"Chilled stash {:?} has less stake ({:?}) than minimum role bond ({:?})",
stash,
ledger.active,
Expand All @@ -2159,8 +2223,12 @@ impl<T: Config> Pallet<T> {
(true, false) => {
// Nominators must have a minimum bond.
if ledger.active < Self::min_nominator_bond() {
*nominator_total += 1;
if nominator_undermin.len() < MAX_EXAMPLES {
nominator_undermin.push(stash.clone());
}
log!(
warn,
trace,
"Nominator {:?} has less stake ({:?}) than minimum role bond ({:?})",
stash,
ledger.active,
Expand All @@ -2171,8 +2239,12 @@ impl<T: Config> Pallet<T> {
(false, true) => {
// Validators must have a minimum bond.
if ledger.active < Self::min_validator_bond() {
*validator_total += 1;
if validator_undermin.len() < MAX_EXAMPLES {
validator_undermin.push(stash.clone());
}
log!(
warn,
trace,
"Validator {:?} has less stake ({:?}) than minimum role bond ({:?})",
stash,
ledger.active,
Expand Down
Loading