Skip to content

CIP-0193? | Auto-retirement of Abandoned Pools - #1230

Open
Cerkoryn wants to merge 7 commits into
cardano-foundation:masterfrom
Cerkoryn:stale-stake
Open

CIP-0193? | Auto-retirement of Abandoned Pools#1230
Cerkoryn wants to merge 7 commits into
cardano-foundation:masterfrom
Cerkoryn:stale-stake

Conversation

@Cerkoryn

@Cerkoryn Cerkoryn commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

This CIP is an idea taken straight out of the Shelley Ledger Spec, Appendix C (ed: page 51) with minimal changes. It is recommended to read that short section in its entirety to understand the context of the problem this CIP aims to solve.

In short, we estimate roughly 43 blocks per epoch are missed and 41.88M worth of pool stake will always vote implicit NO on relevant governance actions due to abandoned pools. This CIP mitigates that using a similar mechanism to what is described in the ledger spec, but instead of gating by a pool stake threshold (which is harder to implement) it simply allows any non-abandoned pool to bypass pruning by submitting a pool registration update.

(rendered)

@Cerkoryn

Copy link
Copy Markdown
Contributor Author

Tagging @brouwerQ and @GNP1-dev for review since I used much of their valuable input while drafting this CIP.

@rphair rphair added Category: Ledger Proposals belonging to the 'Ledger' category. State: Triage Applied to new PR afer editor cleanup on GitHub, pending CIP meeting introduction. labels Jul 20, 2026

@rphair rphair left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@Cerkoryn I've given this proposal a full read and would support its candidacy & progression as far as Ledger review will permit.

  • @lehins my apologies for not tagging you early enough for a whole day of review before CIP meeting Triage (https://hackmd.io/@cip-editors/139) but even a quick reply, if you're able, might help us properly declare this as a CIP candidate or hold off pending a design change.

I've read "Appendix C" and I think your re-registration option provides a greater failsafe vs. setting a probability threshold alone: which would be challenged by many legitimate circumstances, no matter how generously this might be set.

  • At first glance I was thinking of events in my own pool of probability less than 1/10000 that happened once or twice: therefore it's reassuring that very small pools can re-register to keep themselves alive no matter what kind of odds may be against their producing a block.

I have a review tagging list in mind & maybe we can add some more choices to it at the CIP meeting tomorrow (after hopefully Ledger confirmation + a quick check to see that wallets aren't making assumptions about re-delegation events (as raised below)).

Comment thread CIP-XXXX/README.md Outdated
Comment on lines +230 to +232
| 73 epochs | One year | 1,485 | 41.88M ADA |

At 73 epochs, the candidate population is approximately half of all registered pools but represents only about 0.20% of active stake in the snapshot. This indicates a large long tail of registrations with little stake. Compared with a 12-epoch value, the one-year period reduces affected active stake by approximately 37.78 million ADA while still addressing most of the potentially stale pool registrations. It is therefore a conservative initial value that minimizes disruption to active stake while establishing a finite lifetime for pools that show no activity for a full year.

@rphair rphair Jul 20, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If @Cerkoryn you & reviewers agree, you might also add the social / human factor that an annual / recurring calendar date requirement to re-register a non-block-producing pool would offer the advantage of being easier for operators to remember & schedule.

Conversely, I do also think that the ½, ⅓, and ⅙ year intervals are going to scoop up greater numbers of active pools in the dragnet: not just from low stake but also from other baffling circumstances that I recall even @GNP1-dev's pool faced at one point.

@Cerkoryn Cerkoryn Jul 21, 2026

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.

I shared this in the CIP Editors Meeting chat, but left it in simpler table format in the actual CIP.

Even though there's not a lot of affected stake, there is a huge amount of potential pools that could be affected. Since this change would go into effect presumably all at once, then many/most of those pools would be pruned at the same time. And that would likely be the annual calendar date people remember to renew their pool activity.

image

(ignore the vertical line, I was originally leaning toward 36 epochs until I saw the amount of pools potentially affected 😅 )

@rphair rphair Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

yes, and I think the number of abandoned pools to be closed could help provide a more realistic perception of the network. I don't think this goal is irrelevant to the CIP motivation because the long-held peer advice that "anyone can create a stake pool" without full disclosure of the difficulties has led to this historical aberration: which could someday recur with a similar bull-market stimulus. Making it more public that a new pool might not produce a block in a 1-year period is an important statement in itself.

Comment thread CIP-XXXX/README.md Outdated

No new CLI certificate command is required. An operator may renew activity using the existing pool registration workflow and the pool's current parameters.

### Versioning and backward compatibility

@rphair rphair Jul 20, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

(or whatever topic this relates to the most)

One thing I most appreciate about this method is that it doesn't, and shouldn't need to, specify "what wallets should do" because the pool expiration event should simply make a wallet look un-delegated as all wallets originally are.

But I still think we would have to check with wallet implementors in review that they don't either:

  • store the delegation in their own state until there's a deliberate re- or un-delegation;
  • scan the chain for explicit delegation transactions to determine current delegation state.

Some of these assumptions may have been considered reasonable before: but this CIP would change that. So if there's a chance that wallet practice could be doing these things, some recommendations for wallets' accommodation of the CIP would also have to be included.

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.

This was the reasoning for having the ledger expose...

poolExpiration : PoolKeyHash -> Epoch

The thought is that this makes it an extremely simple lookup from basically any indexing tool to check without having to rely on external state tracking.

@rphair rphair Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Very good... but does this mean that the Path to Active item

Supported node, CLI, and indexing interfaces expose spoActivity and poolExpiration.

should be accompanied by an item like (?):

Wallet providers are advised to use spoActivity and poolExpiration to determine delegation status.

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.

I could add that in if you like? I wasn't sure if that would be in scope for a ledger-facing CIP like this.

@rphair rphair Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The implementation work faces the Ledger, but the changes also face the wallet community... and in other cases like this we've definitely included notification to — and some of those cases, approval from — the affected communities.

So yes I do think it would be in scope & would suit the Path to Active: although we might accomplish that advisement in advance during CIP review & if so you'd be welcome to tick that box before merge. cc @AlexDochioiu @francisluz @MarcelKlammer @zuzunker

@kenerik

kenerik commented Jul 21, 2026

Copy link
Copy Markdown

Tagging myself here.
This could be a intersect CIVICS thing to look into as well.
@Cerkoryn would you be interested in explaining this for the commetee in a few weeks?
Explaining the governance impact of this.

@lehins lehins left a comment

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.

It is a very clear and well written CIP 👍
It would be fairly straightforward to implement.
I only had one question that I believe should be clarified, whihc has to do with counting casted votes as legitimate activity for expiration renewal. Other than that no objections from the Ledger side.

Comment thread CIP-XXXX/README.md Outdated

`poolExpiration` MUST have an entry for every registered pool. It records the epoch boundary at which the pool will be pruned unless qualifying activity renews it.

### Activity updates

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.

Should casting a manual vote on a governance action be considered as an activity that resets the counter?
I really doubt that there will be such pools that make no blocks, but go out of their way to vote on governance actions 😄 Nevertheless, that could still be considered as participation in the Cardano protocol.
If so, then we should also mention how this CIP would interplay with CIP-175
Naturally automatic No or AlwayAbstain or AlwaysNoConfidence could not be considered as activity.

@Cerkoryn Cerkoryn Jul 21, 2026

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.

I actually had that in my original draft, but removed it basically for the concern you described 😅

As an SPO, their primary job is to make blocks and it would be odd for them to turn their pool on, vote, and then turn it off again to continue missing blocks.

CIP-175 was another thought I had, but I wasn't sure if it would complicate things. If we allow voting on a GovAction to reset the counter, should it be the cold key only? Or both cold and hot keys?

I'm not sure how feasible it would be for the hot key, and there are weird edge cases where you've delegated your vote to somebody else and then abandon your pool.

If we can find satisfactory resolution to that then I'm happy to add governance voting back in as another way to reset the spoActivity counter.

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.

I was mostly commenting about this because we need to make sure it is explicitly listed here either one way or another.

Here is my personal take on the two options that we have:

  1. Naturally, it would be easier to exclude votes from being considered as an activity that resets the SPO expiration. Less implement the better. 😄
  2. Technically speaking we could include voting with a cold key to reset the counter, but only with the cold key. Since otherwise, once we have CIP-175, an inactive SPO would be able to authorize a hot credential and let someone else do the voting on their behalf indefinitely.

So, my personal hunch is to go with option 1 and mention in the CIP that option 2 was considered.

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.

I am fine with option 1 as well. I will update the CIP to mention that option 2 was considered.

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.

I don't think it is a good idea to reset based on votes anyway. If they are consistently failing to create blocks for an entire year, they should be pruned due to dereliction of duty.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

yeah agree with option 1 - and for the sake of emplementing accounting for CIP 175 in the pipeline

Comment thread CIP-XXXX/README.md Outdated
- A registration update proves cold-key control, not that the pool's block-producing node is online. An operator can remain registered while deliberately not producing blocks by periodically re-registering.
- Automatic pruning is not slashing. No pool deposit, rewards, or delegated principal are confiscated.
- Pruning does not move delegated ADA or select a new pool for it. The stake remains spendable but does not participate in staking or earn new pool rewards until its owner redelegates.
- Initializing every registered pool with the same activation-derived expiration can cause many abandoned pools to be pruned at the same boundary.

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.

This shouldn't be an issue, since they aren't making any blocks anyways. Maybe worth noting that.

@rphair rphair changed the title CIP-???? | Pruning Abandoned Pools CIP-0193? | Pruning Abandoned Pools Jul 22, 2026

@rphair rphair left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@Cerkoryn I've just double-checked your prompt & comprehensive summary of the CIP discussion at the meeting today: positive enough to declare this a candidate and commit to widespread review. We look forward to whatever review develops from exposure in governance circles... maybe it could also be presented at the SPO monthly marketing call?

Thanks also @lehins for getting us started properly with a Ledger confirmation about feasibility.

  • FYI @qnikst re: CIP-0165 — is this new Ledger "state" for pools something that should be added to the Canonical Ledger State... especially since it's likely to be a commonly queried item?

We have also not been able to rule out that wallets will need to adjust to a different means of delegation query (re: #1230 (comment)) so please @AlexDochioiu @francisluz @MarcelKlammer @zuzunker have an early look and let us know if there are any wallet design or UX issues that we should include in the discussion.

Please @Cerkoryn rename the containing directory to CIP-0193 and update the "rendered" link in your OP 🎉

Comment thread CIP-XXXX/README.md Outdated
@rphair rphair added State: Confirmed Candiate with CIP number (new PR) or update under review. and removed State: Triage Applied to new PR afer editor cleanup on GitHub, pending CIP meeting introduction. labels Jul 22, 2026
@qnikst

qnikst commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

@rphair thanks for the note. Me and team will take it into the consideration.

I have discussed workflow for that with ledger team, and in order to reduce the amount of work we need to do on the changes. Will it be acceptable to move the source of truth for the CDDL definition to the cardano-ledger repository, seems it's the best place to be the source of truth in forseable future.

If it's acceptable I'll do one update to Cardano Canonical Ledger State CIP and we will avoid extra review for each era/change in the CIP.

@brouwerQ

Copy link
Copy Markdown

@Cerkoryn Thnx for doing the work of putting this CIP together! This was already discussed months (or even more than a year) ago in an SPO group on Telegram and I've also tweeted about this before, but nobody took any further steps before, so happy to see this! 👏👏

Some further remarks and suggestions:

  1. For consistency with other parameters, I would call the parameter something like stakePoolInactivity, poolInactivity, stakePoolInactivityPeriod or poolInactivityPeriod. Inactivity instead of activity, because we also use that for the parameter that controls DRep inactivity, we should be consistent, and stakePool or pool, because the ledger is only aware of what happens with the stake pool, not what happens with the SPO.

  2. I think something like auto-retirement is a better and clearer term than pruning because the consequences are essentially the same as a retiring your pool. The fact that you also speak of explicit retirement somewhere in the text, enforces this imho.

  3. Explicit retirement happens at the end of the specified epoch if I'm correct. This has to do with the timing of determining the used stake distribution and leadership schedule. I think you should be clearer on how this will work with auto-retirement. E.g. if you become inactive in epoch X, what is the last epoch you are counted in the stake distribution and what is the last epoch you can reset the counter by minting a block or submitting a pool update?

  4. Set union ensures that a pool appearing in both sets is processed only once. An explicit retirement takes effect first when its announced epoch is earlier than the pruning deadline; automatic pruning takes effect first when the inactivity deadline is earlier.

    Isn't a retirement certificate also a kind of pool update which resets the counter? If you add an extra requirement that spoActivity/stakePoolInactivityPeriod should be at least poolRetireMaxEpoch (or maybe poolRetireMaxEpoch + 1), an explicit retirement would always take precedence.

    • Increasing spoActivity does not extend an existing expiration unless the pool renews before that expiration.
    • Decreasing spoActivity does not shorten an existing expiration. The pool adopts the shorter interval when it next renews.

    Isn't it more logical that a parameter change also changes the inactivity epochs of all pools? How does it work now when the drepInactivyPeriod parameter is changed, maybe it should work the same? I can find arguments for both implementations...

  5. I wouldn't count voting as a way to reset the counter, as already highlighted, it would be strange if an SPO takes part in voting, but doesn't participate in block production. If it's decided that voting is a way to reset the counter, only voting with your cold key should reset it, like @lehins suggested. All reset actions should prove that you have still access to your cold key imho, because if not, the chain density risks remain.

  6. I would go a bit deeper into the small pool case in the Initial value section (or elsewhere) and add the following:

    Lower values have two effects. Firstly, more pools (with a higher stake) will need to submit a pool update as there will be more pools that don't have a block scheduled before becoming inactive. Secondly, smaller pools that already would've needed to submit a pool update with a higher value, will need to submit more pool updates with a lower value. Intuitively a value of 73 epochs (1 year) seems a good compromise, as in practice it means a small SPO will at most have to sign a pool update certificate every 4 KES periods, for which access to the cold key is already required.

    We could do some more chain analysis and/or fancy probability calculations to determine how many pools would be affected for other values and determine a better value that way, but I would just take the pragmatic route and use the 73 epochs. Needing to sign a pool certificate once a year isn't that big of an extra ask for the smaller pools and the chain is already running for much longer without any dramatic effects on chain density. If we see chain density becoming too low, we can always adjust the parameter accordingly (this would work better if a parameter change does update all expirations though).

  7. I would add a constitutional guardrail that the minimum value for spoActivity/stakePoolInactivityPeriod should be the number of max. KES periods converted to epochs (I think this can be put in a formula with parameters). This to ensure a small SPO never needs to access the cold keys/airgapped machine more than what is needed now.
    If poolRetireMaxEpoch also is taken into account like proposed in point 5, this should also be in the constitutional guardrail of course.

  8. As I said before, the ideas from this CIP where discussed before in an SPO group on Telegram. But some were making it too complicated by suggesting to look at how many KES rotations have happened on-chain. As those are only advertised when minting a block, just looking at produced blocks is much more simple and also more flexible. Taking into account pool updates is needed in both mechanisms btw. I would make a small reference to this idea and highlight the fact that just looking at the bocks is better, just for completeness.

@brouwerQ

Copy link
Copy Markdown
  1. Inactivity instead of activity, because we also use that for the parameter that controls DRep inactivity, we should be consistent

I've been made aware that there is inconsistency in this naming between the constitution and the source code. So for some consistency, we could apply the same inconsistency to this new parameter... 😛

@GNP1-dev

Copy link
Copy Markdown

@Cerkoryn @rphair @brouwerQ flagging an update, since this CIP references my Non-Producing Pool Monitor.

I found and fixed a bug in the tool on 24 July 2026. It was reading stake and pledge figures from an epoch stake snapshot that was still being written, rather than the most recent completed one. Because Cardano writes that snapshot progressively across the epoch, the tool was reporting from partial data and its figures shifted between page loads.

Corrected figures, as at epoch 646: 31 registered pools holding 500,000 ADA or more have not produced a block in over two months, holding 48,907,063 ADA between them. A further pool holding 1,252,857 ADA has never produced a block at all, and is now reported separately rather than being silently excluded, giving a combined 32 pools and 50,159,920 ADA. The corrected numbers are higher than what the tool previously showed.

I have also split the pledge status into four states rather than two. The old single "unmet" bucket merged two quite different situations: an operator who no longer holds the pledge, and one who still holds it but has delegated it to another pool. The second is a configuration choice and is not evidence of abandonment. Current breakdown is 25 met, 1 held but not delegated to the pool, 6 shortfall, 0 unknown.

The page now displays the source epoch and generation time alongside the data, so any figure quoted from it can be pinned to a specific snapshot.

To be clear, this does not affect the figures in the CIP itself. The 1,485 pools and 41.88M ADA come from Cerkoryn's Koios snapshot at epoch 642, and the roughly 43 blocks per epoch figure is arithmetic on that stake share, not output from my tool. I am noting the correction here simply because the tool is cited and anyone who looked at it before today may have seen inconsistent numbers.

https://server-tools.grahamsnumberplus1.com/non_producing_pools_V1.html

@brouwerQ

Copy link
Copy Markdown

I have also split the pledge status into four states rather than two. The old single "unmet" bucket merged two quite different situations: an operator who no longer holds the pledge, and one who still holds it but has delegated it to another pool. The second is a configuration choice and is not evidence of abandonment. Current breakdown is 25 met, 1 held but not delegated to the pool, 6 shortfall, 0 unknown.

Pledge met or not is irrelevant here I think, as those pools can still mint valid blocks, they're just not rewarded for them; chain density remains unaffected.

@Cerkoryn

Copy link
Copy Markdown
Contributor Author

@brouwerQ

I think something like auto-retirement is a better and clearer term than pruning because the consequences are essentially the same as a retiring your pool. The fact that you also speak of explicit retirement somewhere in the text, enforces this imho.

I agree with this and made the change throughout the document. I also made some minor updates to be more clear about precedence during the auto-retirement epoch. My understanding regarding drepActivity is that it does not retroactively change the values, otherwise it would require a lot of re-calculation upon enactment of a parameter change.

I intentionally left the Constitution/Guardrails stuff out of scope here, but I agree with your take nonetheless.

@Cerkoryn Cerkoryn changed the title CIP-0193? | Pruning Abandoned Pools CIP-0193? | Auto-retirement of Abandoned Pools Aug 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Category: Ledger Proposals belonging to the 'Ledger' category. State: Confirmed Candiate with CIP number (new PR) or update under review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants