Skip to content

Raise offence queue eras bound limit#11435

Merged
cirko33 merged 26 commits intomasterfrom
cirko33-offence-queue-raise-limit
Mar 31, 2026
Merged

Raise offence queue eras bound limit#11435
cirko33 merged 26 commits intomasterfrom
cirko33-offence-queue-raise-limit

Conversation

@cirko33
Copy link
Copy Markdown
Member

@cirko33 cirko33 commented Mar 19, 2026

Fixes a bug where OffenceQueueEras bound (BondingDuration) was incorrect when SlashDeferDuration=0. The oldest reportable offence era formula allowed more eras than the bound could hold.

@cirko33
Copy link
Copy Markdown
Member Author

cirko33 commented Mar 19, 2026

/cmd prdoc --audience runtime_dev --bump patch

@cirko33 cirko33 self-assigned this Mar 19, 2026
@cirko33
Copy link
Copy Markdown
Member Author

cirko33 commented Mar 19, 2026

/cmd prdoc --audience runtime_dev --bump minor --force

@cirko33 cirko33 added the A4-backport-stable2603 Pull request must be backported to the stable2603 release branch label Mar 19, 2026
@sigurpol
Copy link
Copy Markdown
Contributor

Few comments:

@cirko33
Copy link
Copy Markdown
Member Author

cirko33 commented Mar 20, 2026

/cmd bench --pallet pallet_staking_async --runtime asset-hub-westend

@github-actions
Copy link
Copy Markdown
Contributor

Command "bench --pallet pallet_staking_async --runtime asset-hub-westend" has started 🚀 See logs here

…t_staking_async --runtime asset-hub-westend'
@github-actions
Copy link
Copy Markdown
Contributor

Command "bench --pallet pallet_staking_async --runtime asset-hub-westend" has finished ✅ See logs here

Details

Subweight results:
File Extrinsic Old New Change [%]
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs set_staking_configs_all_remove 8.12us 805.28us +9817.19
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs set_staking_configs_all_set 8.89us 805.70us +8959.91
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs prune_era_stakers_paged 385.92us 12.81ms +3219.05
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs set_validator_count 4.03us 103.03us +2455.18
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs prune_era_stakers_overview 399.79us 10.16ms +2442.31
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs set_min_commission 4.10us 102.96us +2412.40
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs prune_era_claimed_rewards 419.64us 10.18ms +2325.32
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs prune_era_validator_prefs 426.54us 10.17ms +2283.41
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs prune_era_validator_slash_in_era 417.46us 6.28ms +1403.44
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs prune_era_single_entry_cleanups 48.32us 384.41us +695.49
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs kick 2.36ms 18.14ms +669.43
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs deprecate_controller_batch 45.77ms 334.39ms +630.54
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs prune_era_validator_reward 46.04us 282.25us +513.09
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs prune_era_reward_points 46.11us 281.86us +511.24
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs validate 161.42us 913.96us +466.21
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs set_controller 77.23us 427.51us +453.55
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs force_new_era 21.74us 115.58us +431.69
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs force_new_era_always 22.01us 115.63us +425.30
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs force_no_eras 22.65us 115.54us +410.04
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs bond 162.70us 666.82us +309.85
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs restore_ledger 114.86us 430.86us +275.14
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs withdraw_unbonded_update 181.11us 609.86us +236.74
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs set_payee 61.30us 188.83us +208.03
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs update_payee 75.53us 223.85us +196.35
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs migrate_currency 169.85us 478.55us +181.76
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs force_apply_min_commission 67.31us 187.29us +178.25
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs rc_on_offence 57.11ms 147.50ms +158.26
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs apply_slash 34.48ms 43.99ms +27.59
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs chill 5.96ms 1.03ms -82.78
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs rc_on_session_report 11.44ms 1.88ms -83.57
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs reap_stash 13.40ms 1.87ms -86.05
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs withdraw_unbonded_kill 14.83ms 1.95ms -86.85
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs unbond 10.29ms 1.25ms -87.81
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs nominate 13.24ms 1.61ms -87.83
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs force_unstake 16.18ms 1.90ms -88.24
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs rebond 10.70ms 1.17ms -89.09
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs bond_extra 13.18ms 1.31ms -90.04
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs chill_other 12.29ms 1.13ms -90.78
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_staking_async.rs process_offence_queue 12.92ms 738.74us -94.28
Command output:

✅ Successful benchmarks of runtimes/pallets:
-- asset-hub-westend: ['pallet_staking_async']

// Minimum execution time: 151_823_000 picoseconds.
Weight::from_parts(162_698_000, 0)
.saturating_add(Weight::from_parts(0, 0))
// Estimated: `4218`
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.

@ggwpez - weights generated by #10794 seemed a bit off. Bunch of Estimated: 0 for example etc
This PR doesn't introduce significant changes and affects only few benchmarks where we actually access the OffenceQueueEras and as expected - we are seeing e.g.

Staking::OffenceQueueEras max_size increased: 917 (added: 504512)    

This is the change from this branch — the raised offence queue limit.
For the rest the results are basically very close to what we have on chain before #10794

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hm weird... I think there is a non-determinism bug somewhere in the PoV benchmarking, but its highly unlikely to trigger for all extrinsics like it did in that MR.
No idea honestly, but can look into it when i have time.

@sigurpol
Copy link
Copy Markdown
Contributor

Few comments:

@kianenigma , @Ank4n wdyt? Kian, in the related issue you were hinting as raising the bound as proper solution. I am fine with that, I would prefer the conversion to Vec + force_from approach but I would like to understand the reason behind your preference (or it was mostly because it was good enough and faster to implement?)

impl<T: Config> Get<u32> for OffenceQueueErasBound<T> {
fn get() -> u32 {
let bonding_duration = T::BondingDuration::get();
bonding_duration.saturating_add(bonding_duration)
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.

Maybe we should take a min of this and something like 10, so its never 0.

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.

Actually, we don't need to double it, we just need to add few eras so the system has time to clear the offences. So, something likebonding_duration.saturating_add(10) will do.

@Ank4n
Copy link
Copy Markdown
Contributor

Ank4n commented Mar 24, 2026

Few comments:

@kianenigma , @Ank4n wdyt? Kian, in the related issue you were hinting as raising the bound as proper solution. I am fine with that, I would prefer the conversion to Vec + force_from approach but I would like to understand the reason behind your preference (or it was mostly because it was good enough and faster to implement?)

IMO this is a non-issue. I don't see how we can exceed BondingDuration. We could try to reproduce the overflow path but I believe it should be impossible unless you manipulate the storage somehow or shorten the era to 1 block or something (so not a practical scenario).

In any case, I don't see any harm in going with this solution . Also benchmark should not really get affected because we still have bonding duration worth of eras.

@sigurpol
Copy link
Copy Markdown
Contributor

sigurpol commented Mar 24, 2026

IMO this is a non-issue. I don't see how we can exceed BondingDuration. We could try to reproduce the overflow path but I believe it should be impossible unless you manipulate the storage somehow or shorten the era to 1 block or something (so not a practical scenario).

In any case, I don't see any harm in going with this solution . Also benchmark should not really get affected because we still have bonding duration worth of eras.

IIUC, this is true for polkadot / any real current runtime configuration.
But can OffenceQueueEras bound overflow with SlashDeferDuration = 0 ?

Let's consider this example:

  • BondingDuration = 3:
  • active_era = 3
  • SlashDeferDuration = 0

In this case:

  • oldest_reportable_offence_era = active_era.index.saturating_sub(T::BondingDuration::get()) = 3 - 3 = 0
  • OffenceQueueEras is bounded at BondingDuration=3 (on master, not on this PR!)

The check here discards new offences if offence_era < oldest_reportable_offence_era.

With oldest_reportable_offence_era = 0, offences for eras 0, 1, 2, 3 are all accepted because (offence_era >= oldest_reportable_offence_era).

After three offence reports arrive (one each for eras 0, 1, and 2), OffenceQueueEras = [0, 1, 2] => the vec is at its bound of 3 (again, not on this PR, but on master!).

A fourth offence report for era 3 arrives => it is inserted into OffenceQueue, but try_insert into OffenceQueueEras fails silently.

Do I get it right?

If my example makes sense (maybe it's just theoretical / not plausible / not possible / I get something seriously wrong - all very possible 😄 ), then this PR makes the code more robust and maybe it's worth adding a similar test to prove it.
But maybe the point of the original issue is to make this class of issues from unrealistic because of current runtime configuration to impossible by construction replacing the try_insert with conversion to vec + force_from

Comment thread substrate/frame/staking-async/src/pallet/impls.rs Outdated
Comment thread substrate/frame/staking-async/src/pallet/mod.rs Outdated
Comment thread substrate/frame/staking-async/src/pallet/mod.rs Outdated
Comment thread prdoc/pr_11435.prdoc Outdated
Comment thread substrate/frame/staking-async/src/tests/slashing.rs
Comment thread substrate/frame/staking-async/src/pallet/mod.rs Outdated
@cirko33 cirko33 enabled auto-merge March 29, 2026 09:21
}
}

const OFFENCE_QUEUE_ERAS_BOUND: u32 = 10;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What is the purpose of this? Why is it 10? Why isn't it used anywhere besides the Get impl below?

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.

The scope could be limited since it's used only in the get impl below indeed - that came from (my 😅 ) comment where magic number 10 was used in two different places - but can be revised and kept where it is used only.
About why 10 and not 20, or 2*bonding_duration or anything else - this is very arbitrary. My understanding of this issue - but please @Ank4n , and @cirko33 (these days at EthCc so might not answer promptly) is that

  1. the original issue reporting during audit is not a realistic one since we have 1 era to apply all slashes in an era and so it is practically impossible for count to exceed BondingDuration.
  2. considering the above, the scope of WeakBoundedVector here is not to protect against offence spam vs slow processing but rather being robust in case during a runtime upgrade we lower BondingDuration and then we still want to be sure to be able to process offences from old eras that wouldn't fit in the post-RU OffenceQueueEras. Now, 10 is a magic number that might or might not work in this case and whatever number might not be good enough here. If we want to be more robust, and we still don't want to go for the hackish way of going through Vec conversion + force_from() discussed in other comments in this PR, one could assume that in the case someone wants to lower BondingDuration, it must provides also an ad-hoc migration or something like that.

Wdyt?

@cirko33 cirko33 added this pull request to the merge queue Mar 31, 2026
Merged via the queue into master with commit de0a245 Mar 31, 2026
320 of 328 checks passed
@cirko33 cirko33 deleted the cirko33-offence-queue-raise-limit branch March 31, 2026 18:07
paritytech-release-backport-bot Bot pushed a commit that referenced this pull request Mar 31, 2026
Fixes a bug where **OffenceQueueEras** bound (BondingDuration) was
incorrect when `SlashDeferDuration=0`. The oldest reportable offence era
formula allowed more eras than the bound could hold.

---------

Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com>
(cherry picked from commit de0a245)
@paritytech-release-backport-bot
Copy link
Copy Markdown

Successfully created backport PR for stable2603:

lexnv added a commit that referenced this pull request Apr 1, 2026
Squashed commit of the following:

commit 1b3ad0b
Author: Alexandru Vasile <alexandru.vasile@parity.io>
Date:   Wed Apr 1 10:55:36 2026 +0000

    Adjust metrics

    Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

commit 61d37db
Author: Alexandru Vasile <alexandru.vasile@parity.io>
Date:   Wed Apr 1 09:58:38 2026 +0000

    metrics: Bump some other buckets

    Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

commit ab2a221
Author: Alexandru Vasile <alexandru.vasile@parity.io>
Date:   Wed Apr 1 09:57:11 2026 +0000

    collator-proto/metrics: Fix blindspot in collation fetch latency metrics

    Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

commit 0d6888a
Author: Ankan <10196091+Ank4n@users.noreply.github.com>
Date:   Wed Apr 1 00:18:21 2026 +0200

    Implement Budget Distribution logic in pallet-dap (#11527)

    Stacked on #11513.
    Extracted from #10844.

    ## Overview

    Adds issuance drip and budget distribution to `pallet-dap`. DAP becomes
    a generic inflation engine: it mints new tokens on a configurable
    cadence and distributes them to registered budget recipients.

    No runtime behavior change: the existing chain configuration continues
    to mint via `EraPayout` trait in staking. DAP can be configured as a
    noop (cadence = 0 or empty budget).

    ## Changes

    ### pallet-dap
    - **Issuance drip**: `drip_issuance()` runs in `on_initialize`. Computes
    mint amount via `IssuanceCurve` (total issuance + elapsed time) and
    distributes to `BudgetRecipient`s per a governance-updatable
    `BudgetAllocation` map that must sum to 100%.
    - **Safety guards**: `MaxElapsedPerDrip` ceiling prevents over-minting
    if the chain stalls. First-block initialization skips drip to avoid
    minting for an unknown period.
    - **Buffer accounting**: buffer's share is deactivated on inflow (mint +
    `OnUnbalanced` slashes).
    - **`set_budget_allocation`** extrinsic (root-only): validates keys
    match registered recipients and percentages sum to exactly 100%.
    - **`BudgetRecipient` impl**: DAP exposes its buffer as a recipient
    (key: `"buffer"`).
    - **Migration**: `MigrateV1ToV2` seeds `LastIssuanceTimestamp` and
    `BudgetAllocation` for existing chains. Not wired up in WAH or other
    runtimes yet.

    ## TODOs
    - [x] Wire benchmark weights.

    ## In Later PR
    - Revert [these
    changes](9b388b2)

    ---------

    Co-authored-by: Paolo La Camera <paolo@parity.io>

commit 8b53323
Author: Javier Viola <363911+pepoviola@users.noreply.github.com>
Date:   Tue Mar 31 21:26:58 2026 +0200

    bump zombienet version to v0.4.9 (#11569)

    This version move the internal monitor to a diff log target, eliminating
    the current spam of tracing logs.

    Thx!

    ---------

    Co-authored-by: Bastian Köcher <git@kchr.de>

commit 129a48a
Author: Ankan <10196091+Ank4n@users.noreply.github.com>
Date:   Tue Mar 31 19:06:21 2026 +0200

    [Staking] Add issuance and budget traits in prep for Budget Split (#11513)

    # Overview

    Moves `EraPayout` trait to `sp-staking` and adds new traits for
    issuance, budget distribution, and reward calculation.

    Extracted changes from the main PR: #10844
    Also see: #11512

    ## Changes

    ### sp-staking
    - `EraPayout`: moved from `pallet-staking` and `pallet-staking-async` to
    `sp-staking`, eliminating the duplicate definitions.
    - `budget` module: stake independent traits:
    - `IssuanceCurve`: successor to `EraPayout`, computes issuance from
    total supply + elapsed time (no staking state dependency).
    - `BudgetRecipient` / `BudgetRecipientList`: register pot accounts for
    inflation distribution. Runtime wires as a tuple.
      - `BudgetKey`: bounded identifier for budget categories.
    - `StakerRewardCalculator`: trait for calculating validator incentive
    weights and staker reward splits.

    ### pallet-staking / pallet-staking-async
    - Removed local `EraPayout` definitions, re-exported from `sp-staking`.

    ---------

    Co-authored-by: Paolo La Camera <paolo@parity.io>

commit 10a517e
Author: Dmitry Markin <dmitry@markin.tech>
Date:   Tue Mar 31 18:37:01 2026 +0300

    Implement `bitswap_v1_get` RPC method (#11521)

    Implement `bitswap_v1_get` RPC method according to the
    [spec](https://github.com/paritytech/json-rpc-interface-spec/blob/main/src/api/bitswap_v1_get.md).

    ---------

    Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com>
    Co-authored-by: Lukasz Rubaszewski <117115317+lrubasze@users.noreply.github.com>

commit 2c99855
Author: Paolo La Camera <paolo@parity.io>
Date:   Tue Mar 31 16:42:03 2026 +0200

    Fix can_inc_consumer check blocking session key rotation in pallet_session (#11573)

    Check consumer capacity only when we actually increment the consumer
    count (first-time local registration or external-to-local transition),
    not on key rotation.

    Notes:
    1. setting keys via `stakingRcClient` didn't suffer of this issue since
    by-pass `do_set_keys()`
    2. setting and purging keys via session pallet directly on RC is
    deprecated and will be removed soon - but better safe than sorry till
    then

    ---------

    Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com>

commit de0a245
Author: Luka Ciric <luka.ciric2106@gmail.com>
Date:   Tue Mar 31 16:39:48 2026 +0200

    Raise offence queue eras bound limit (#11435)

    Fixes a bug where **OffenceQueueEras** bound (BondingDuration) was
    incorrect when `SlashDeferDuration=0`. The oldest reportable offence era
    formula allowed more eras than the bound could hold.

    ---------

    Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com>
    Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com>

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
cirko33 added a commit that referenced this pull request Apr 3, 2026
Backport #11435 into `stable2603` from cirko33.

See the
[documentation](https://github.com/paritytech/polkadot-sdk/blob/master/docs/BACKPORT.md)
on how to use this bot.

<!--
  # To be used by other automation, do not modify:
  original-pr-number: #${pull_number}
-->

Co-authored-by: Luka Ciric <luka.ciric2106@gmail.com>
Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com>
franciscoaguirre pushed a commit that referenced this pull request Apr 7, 2026
Fixes a bug where **OffenceQueueEras** bound (BondingDuration) was
incorrect when `SlashDeferDuration=0`. The oldest reportable offence era
formula allowed more eras than the bound could hold.

---------

Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A4-backport-stable2603 Pull request must be backported to the stable2603 release branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants