Implement 'Hard Pressure' Issuance Model#898
Conversation
Moved rc_reserve, rc_free_min definition closer to its usage to reduce cognitive load while reading the code. - [x] Does not require a CHANGELOG entry --------- Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Changes: - Rebase and delete some stuff that currently wont compile, can do more throughout cleanup afterwards - [ ] Does not require a CHANGELOG entry --------- Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Bastian Köcher <git@kchr.de> Co-authored-by: Yuri Volkov <0@mcornholio.ru> Co-authored-by: s0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Branislav Kontur <bkontur@gmail.com> Co-authored-by: GitHub Action <action@github.com> Co-authored-by: Muharem <ismailov.m.h@gmail.com> Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com> Co-authored-by: Adrian Catangiu <adrian@parity.io> Co-authored-by: fellowship-merge-bot[bot] <151052383+fellowship-merge-bot[bot]@users.noreply.github.com> Co-authored-by: Pablo Andrés Dorado Suárez <hola@pablodorado.com> Co-authored-by: ordian <write@reusable.software> Co-authored-by: Alistair Singh <alistair.singh7@gmail.com> Co-authored-by: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Co-authored-by: Bastian Köcher <info@kchr.de> Co-authored-by: Serban Iorga <serban@parity.io> Co-authored-by: Xiliang Chen <xlchen1291@gmail.com> Co-authored-by: Nikolai Kozlov <1431590+nkpar@users.noreply.github.com> Co-authored-by: nkprt <nikolai@parity.io>
Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Add vesting tests with pre/post migration checks - [x] Does not require a CHANGELOG entry --------- Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Add pre/post migration checks to bags_list and conviction_voting - [x] Does not require a CHANGELOG entry
Treasury pallet data migration from Relay Chain to Asset Hub. For more info refer to the treasury.md file --------- Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
- Just emit a warning when relay chain storage item are not found on asset hub, since this may be caused by legit preimage unrequests performed by other pallets (e.g., by pallet scheduler) - Just emit a warning when asset hub storage item was not on the relay chain, since this may have been added when migrating referenda that did not pass on the relay chain - Allow requested preimage items on the relay chain to become unrequested on Asset Hub for the same reason (but not the other side)
Reporting CSV generation to track test coverage. See paritytech/ahm-dryrun#14 --------- Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
…s#648) PR includes: - Deactivate/reactivate total issuance that should not be included into total support for Governance (existing logc from Relay Chain); - Set `InactiveIssuance` on RC after migration to zero; - generate and use actual weights for new pallets; - address minor TODOs; - add TODOs for XCM migration; --------- Co-authored-by: GitHub Action <action@github.com>
<!-- Remember that you can run `/merge` to enable auto-merge in the PR --> <!-- Remember to modify the changelog. If you don't need to modify it, you can check the following box. Instead, if you have already modified it, simply delete the following line. --> - [x] Does not require a CHANGELOG entry Add `sudo` behind `zombie-bite-sudo` feature to use with zombie-bite for migration tests. cc: @ggwpez --------- Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Add pre/post migration checks to fast_unstake - [x] Does not require a CHANGELOG entry --------- Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Add pre/post migration checks to asset_rate - [x] Does not require a CHANGELOG entry --------- Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Add tests for the following storage items of pallet treasury: - `ProposalsCount` constant correctly migrated - `SpendCount` constant correctly migrated - `Proposals` length is preserved on Asset Hub with all the proposal IDs - `Approvals` elements are all preserved on Asset Hub - `Spends` length is preserved on Asset Hub and some `Spend` fields are checked (validity interval blocks, asset amount, spend status) **What's NOT tested** - Perfect equality of preserved `Proposals` w.r.t. Relay Chain (they are deprecated and will soon be removed) - `AssetKind` and `Beneficiary` checks on migrated `Spends` (migration logic is involved and would essentially require duplicating the migration code) --------- Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Adding extensive testing coverage on the relay chain, especially for partially migrated accounts. **To Do** Complete checks on total issuance and checking account balance on Asset Hub before and after the migration --------- Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Integrated and adopts the AH migrator pallet's weights to Relay Chain
Part of polkadot-fellows#644 Tests - All storage items don't exist beforehand on AH - That they equal the RC values after migration Notes: I noticed child-bounties isn't migrated. I assume this was on purpose but wanted to note just in case.
Some import aliases to make it easy to port AHM to Westend. Usage is `just port westend ~sdk ~sdk/cumulus/ahm` in the folder with the Justfile of the runtimes repo. --------- Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
…lows#636) Fixes the checking account migration and adds working integration tests. - [x] Does not require a CHANGELOG entry --------- Co-authored-by: giuseppere <giuseppe.re@parity.io>
This will allow upgrading the chains locally for tests. Spec version will change before release. - [X] Does not require a CHANGELOG entry --------- Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Adding missing checks for pallet treasury. Thanks to @PolkadotDom for noticing. --------- Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Add pre/post migration checks to claims and crowdloan - [x] Does not require a CHANGELOG entry --------- Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Asset Hub migrator benchmarks --------- Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: GitHub Action <action@github.com>
Add Call filtering to disable calls on AH during the migration. --------- Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Contains the changes and script to migrate to the code to Westend and run staking migration with `pallet_staking_async`. Runs in CI. --------- Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Checks all storage items for pallet-referenda. Some bespoke logic was required for ReferendumInfoFor that mirrors the migration code.
Cleanup unused benchmarks setup
Westend async staking migration continue. --------- Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Relay Chain migrator benchmarks --------- Co-authored-by: GitHub Action <action@github.com>
Asset Hub ops pallet benchmarks
Xcm send weights and `XcmBatch`, `XcmBatchAndMeter` helper types. Adding XCM send weight handling with as little refactoring as possible. --------- Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
| anomalous_duration, | ||
| ); | ||
|
|
||
| // Capped at MAX_ERA_EMISSION (2 * UNITS) |
There was a problem hiding this comment.
[nitpick] should we remove the (2 * UNITS ) and just leave Capped at MAX_ERA_EMISSION? The actual value would be around ~2.3M DOT but I believe MAX_ERA_EMISSION is expressive enough
There was a problem hiding this comment.
Artifact from writing. Good catch
|
Aside from a minor cosmetic comment, it looks good to me. @kianenigma, @ggwpez, could you please take a final look? 🙏 |
|
We need to run the new weights, correct? |
|
/cmd bench --runtime asset-hub-polkadot --pallet pallet_staking_async |
|
Command "bench --runtime asset-hub-polkadot --pallet pallet_staking_async" has started 🚀 See logs here |
…t --pallet pallet_staking_async'
|
Command "bench --runtime asset-hub-polkadot --pallet pallet_staking_async" has finished ✅ See logs here DetailsSubweight results:
|
| // Minimum execution time: 150_928_000 picoseconds. | ||
| Weight::from_parts(162_392_374, 0) | ||
| // Minimum execution time: 6_097_619_000 picoseconds. | ||
| Weight::from_parts(11_384_471_641, 0) | ||
| .saturating_add(Weight::from_parts(0, 6248)) | ||
| // Standard Error: 39_584 | ||
| .saturating_add(Weight::from_parts(5_149_263, 0).saturating_mul(n.into())) | ||
| // Standard Error: 10_755_226 | ||
| .saturating_add(Weight::from_parts(39_604_011, 0).saturating_mul(n.into())) |
There was a problem hiding this comment.
Is the benchmark server not ref HW?
There was a problem hiding this comment.
I am assuming we end up correctly on runs-on: benchmark as per https://github.com/polkadot-fellows/runtimes/blob/main/.github/workflows/cmd.yml#L223 so seems that one/some of the runners with benchmark label are virtualized and not ref HW (e.g ibp-gb)
…-polkadot --pallet pallet_staking_async'" This reverts commit 24ae3b6.
There was a problem hiding this comment.
Found multiple correctness/maintainability issues in the new Hard Pressure issuance implementation: (1) the post-2026 snapshot of TI is taken lazily at first use which can drift from the intended schedule, (2) precision is unnecessarily truncated in stepped emission calculations, (3) the emission cap can under-mint in legitimate long-era scenarios, (4) the stepped-curve primitive/docs don’t match behavior, and (5) several tests rely on lossy u128->f64 conversions.
Suggestions that couldn't be attached to a specific line
system-parachains/asset-hubs/asset-hub-polkadot/src/staking/mod.rs:324-326,425-426
MAX_ERA_EMISSION is hardcoded to PRE_HARD_CAP_DAILY_EMISSION * 7 and applied unconditionally via .min(Self::MAX_ERA_EMISSION). This can under-mint in plausible “long era” scenarios (e.g., if eras are delayed well beyond a week due to operational issues), silently deviating from time-based inflation. If the goal is a safety fuse, consider a cap that scales with era_duration_millis up to some bounded maximum (e.g., cap_per_day * min(days, MAX_DAYS)) so legitimate long eras don’t get penalized the same way as pathological values.
system-parachains/asset-hubs/asset-hub-polkadot/src/staking/mod.rs:691-706,751-755,857-861,883-887
Several tests cast u128 balances to f64 and then use assert_relative_eq!. For values above 2^53, f64 loses integer precision; these assertions can become insensitive to meaningful planck-level differences or become flaky depending on magnitudes. Prefer integer-based tolerances (e.g., abs_diff <= X in plancks, or compare ratios using fixed-point) to keep tests precise and future-proof.
system-parachains/asset-hubs/asset-hub-polkadot/src/staking/stepped_curve.rs:20-22,80-83
Module docs describe a generic curve “moving towards a target asymptote”, but try_new rejects target < initial_value, meaning decreasing curves are unsupported. Either update the docs to state “increasing-only” explicitly, or support decreasing curves by handling the sign and using abs(diff) semantics (and adjusting last_step_size/evaluate accordingly).
system-parachains/asset-hubs/asset-hub-polkadot/src/staking/stepped_curve.rs:20-22,153-159
Docs imply the curve is asymptotic (“approaches”), but if pct is 100% (Perbill::from_percent(100)), ratio becomes 0 and evaluate reaches the target exactly after one step (not asymptotic). Either forbid pct == 100% in try_new (return Err) or adjust docs/tests to reflect that the target may be reached when pct==100% (and when target==initial).
CHANGELOG.md:15,24
Changelog entries reference PR #898. If this PR number isn’t correct for this repository/branch, it will produce broken links and incorrect attribution. Ensure the PR references match the actual PR number or use a generic reference format consistent with surrounding entries.
| // Get TI from March 14, 2026. | ||
| let starting_ti = March2026TI::get().unwrap_or_else(|| { | ||
| // If first time, store it. | ||
| let current_ti = pallet_balances::Pallet::<Runtime>::total_issuance(); | ||
| // Sanity check to prevent blow-up. Make sure TI is reasonable number. | ||
| if current_ti < Self::FIXED_PRE_HARD_CAP_TI { | ||
| March2026TI::put(Self::FIXED_PRE_HARD_CAP_TI); | ||
| Self::FIXED_PRE_HARD_CAP_TI | ||
| } else { | ||
| March2026TI::put(current_ti); | ||
| current_ti | ||
| } | ||
| }); |
There was a problem hiding this comment.
March2026TI is captured lazily on the first call to yearly_after_hard_cap. If the runtime upgrade enabling this logic happens after the intended start date (or if the first call happens later for any reason), the stored TI won’t correspond to “March 14, 2026” and the entire stepped schedule will be shifted (likely under-issuing vs the referendum-defined curve). Consider setting March2026TI deterministically via an OnRuntimeUpgrade at the upgrade block, or gating capture on relay_block_num == HARD_CAP_START (or within a tight window) and otherwise using a fixed known snapshot value / explicit governance-set constant.
| // The last step size tells us the expected TI increase over the current two year | ||
| // period. | ||
| let two_year_emission_fp = ti_curve.last_step_size(relay_block_fp); | ||
| let two_year_emission: u128 = two_year_emission_fp.into_inner() / FixedU128::DIV; | ||
| FixedU128::from_rational(1, 2).saturating_mul_int(two_year_emission) |
There was a problem hiding this comment.
Post-hard-cap yearly emission truncates FixedU128 precision by converting two_year_emission_fp to u128 via into_inner()/DIV, then halving via saturating_mul_int. This introduces systematic rounding-down that can accumulate over many steps and skew asymptotic behavior. Keep the computation in FixedU128 as long as possible (e.g., let yearly_fp = two_year_emission_fp / 2; and only convert once at the end with an explicit rounding strategy) to avoid unnecessary precision loss.
|
|
||
| impl EraPayout { | ||
| pub(crate) fn impl_experimental_inflation_info() -> InflationInfo { | ||
| //TODO: Update post March 14th, 2026 |
There was a problem hiding this comment.
Leftover production //TODO: Update post March 14th, 2026 in impl_experimental_inflation_info. Since this code is tied to the new issuance model, leaving an unresolved TODO in runtime logic is risky (it’s easy to ship and forget). Either resolve it now or convert it into a tracked issue reference with a clear condition (what exactly becomes incorrect after that date).
| FixedU128::from_u32(80), // initial (moving down towards 50) | ||
| RemainingPct { | ||
| target: FixedU128::from_u32(110), | ||
| pct: Perbill::from_percent(20), // 20% closer each step | ||
| }, | ||
| FixedU128::from_u32(10), // period | ||
| ) | ||
| .unwrap_or_default(); | ||
|
|
||
| // Just before first step (still in period 0) | ||
| assert_eq!(curve.evaluate(FixedU128::from_u32(109)), FixedU128::from_u32(80)); | ||
|
|
||
| // At first step (start + period = 110) | ||
| // Calculation: 50 + (110 - 80) * (1 + 0.20)^1 = 50 + 30 * 1.2 = 50 + 36 = 86 | ||
| let first_step_value = curve.evaluate(FixedU128::from_u32(110)); | ||
| assert_eq!(first_step_value, FixedU128::from_u32(86)); |
There was a problem hiding this comment.
Test first_step_occurs_at_start_plus_period contains misleading comments (e.g., “moving down towards 50” while target is 110, and the calculation comment uses an inconsistent formula). Since this file is meant to be a reusable primitive, these comments are likely to confuse future readers; rewrite the comments to match the implemented formula target - (target-initial)*(1-pct)^n and the actual inputs.
|
/merge |
Auto-Merge-BotUser @sigurpol is not the author of the PR and does not publicly belong to the org Only author or public org members can trigger the bot. |
|
/merge |
2af50d6
into
polkadot-fellows:main
|
Enabled Available commands
For more information see the documentation |
With Ref 1710 - Hard Pressure Capped & Stepped Supply Schedule having passed, we have here an implementation.
The code itself can be reasoned about in roughly 3 parts: