Skip to content

Preserve failed validator incentive vesting payments instead of dropping them#12615

Open
andreitrand wants to merge 5 commits into
andreitrand-validator-vestingfrom
andreitrand-retain-failed-vestings
Open

Preserve failed validator incentive vesting payments instead of dropping them#12615
andreitrand wants to merge 5 commits into
andreitrand-validator-vestingfrom
andreitrand-retain-failed-vestings

Conversation

@andreitrand

Copy link
Copy Markdown
Contributor

The current solution from #12210 is to have vested system payments for validators dropped if there is no vesting capacity available. This was deemed to not be an acceptable solution (see this comment) so this PR proposes an alternative:

  • We derive a deterministic staging account for each individual validator
  • Any system vesting payments that fail due to insufficient capacity deposit their amount as liquid to this staging account (vesting parameters - start and duration - are discarded completely)
  • The very first vested payment appends whatever staged amount is present to its own amount, with the staged amount inheriting the payment's own vesting schedule

@andreitrand andreitrand self-assigned this Jul 9, 2026
@andreitrand andreitrand requested review from a team as code owners July 9, 2026 13:45
@andreitrand andreitrand added T2-pallets This PR/Issue is related to a particular pallet. T14-system_parachains This PR/Issue is related to system parachains. labels Jul 9, 2026
@paritytech-review-bot paritytech-review-bot Bot requested a review from a team July 9, 2026 13:45
Vested payments that can't be processed due to insufficient vesting capacity now get
stored into a staging account unique to that validator. Vesting data (start and duration)
get discarded. The staged amount is colleted and paid together with the very next vested
payment, inheriting the latter's start and duration.
@andreitrand andreitrand force-pushed the andreitrand-retain-failed-vestings branch from c61afd8 to b2ea5d9 Compare July 9, 2026 13:53
@sigurpol

sigurpol commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

One philosophical question: if I get it right, recovery is coupled to a future successful payout. payout_stakers is permissionless, so while a validator is active anyone can trigger the sweep, so far so good.
But a validator who chills/exits and never earns again has no future payout, so their staged funds are stranded indefinitely, is it the case or am I getting it wrong?

@andreitrand

Copy link
Copy Markdown
Contributor Author

One philosophical question: if I get it right, recovery is coupled to a future successful payout. payout_stakers is permissionless, so while a validator is active anyone can trigger the sweep, so far so good. But a validator who chills/exits and never earns again has no future payout, so their staged funds are stranded indefinitely, is it the case or am I getting it wrong?

That's correct - we depend on staking to make at least 1 more successful vested payout after a failed one in order to also grab the latter's balance. This is in line with what we discussed together with @Ank4n, but now that you mention it, it doesn't look ideal.

We could also change the architecture to use a global buffer (a BoundedVec with a reasonable capacity) and write to it all failed vestings (each entry being a schedule & the validator that should receive it), then process it at each era boundary for example. This would prevent the problem you described, but we'd have to figure out what capacity to use on the vector and in the worst case (it gets full), some validators would still miss payments.

@sigurpol

sigurpol commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

That's correct - we depend on staking to make at least 1 more successful vested payout after a failed one in order to also grab the latter's balance. This is in line with what we discussed together with @Ank4n, but now that you mention it, it doesn't look ideal.

We could also change the architecture to use a global buffer (a BoundedVec with a reasonable capacity) and write to it all failed vestings (each entry being a schedule & the validator that should receive it), then process it at each era boundary for example. This would prevent the problem you described, but we'd have to figure out what capacity to use on the vector and in the worst case (it gets full), some validators would still miss payments.

Another random idea: what if on a capacity failure, we merge the amount into the validator's most-recent existing System schedule instead of failing?

@Ank4n

Ank4n commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

om #12210 is to have vested system payments for validators dropped if there is no vesting capacity available. This was deemed to not be an acceptable solution (see this comment) so this PR proposes an alternative:

  • We derive a deterministic staging account for each individual validator
  • Any system vesting payments that fail due to insufficient capacity deposit their amount as liquid to this staging account (vesting parameters - start and duration - are discarded completely)
  • The very first vested payment appends whatever staged am

This is a really good idea. Its less logic as well. Should have just tests to ensure validators don't get any advantage when merging to older schedule.

@andreitrand wdyt?

@andreitrand

Copy link
Copy Markdown
Contributor Author

om #12210 is to have vested system payments for validators dropped if there is no vesting capacity available. This was deemed to not be an acceptable solution (see this comment) so this PR proposes an alternative:

  • We derive a deterministic staging account for each individual validator
  • Any system vesting payments that fail due to insufficient capacity deposit their amount as liquid to this staging account (vesting parameters - start and duration - are discarded completely)
  • The very first vested payment appends whatever staged am

This is a really good idea. Its less logic as well. Should have just tests to ensure validators don't get any advantage when merging to older schedule.

@andreitrand wdyt?

I've updated the logic to now merge a failed vesting schedule's amount with the existing schedule with the closest schedule end. This means that a schedule that can't be added due to capacity now always succeeds, albeit at a potentially different vesting rate. Also, note that this logic applies only to System (trusted) vesting schedules, which remain completely disjoint from public schedules. In the case of the latter, failures due to insufficient capacity still occur but lead to a very visible extrinsic failure.

@paritytech-workflow-stopper

Copy link
Copy Markdown

All GitHub workflows were cancelled due to failure one of the required jobs.
Failed workflow url: https://github.com/paritytech/polkadot-sdk/actions/runs/29099875331
Failed job name: test-doc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T2-pallets This PR/Issue is related to a particular pallet. T14-system_parachains This PR/Issue is related to system parachains.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants