Skip to content

Conversation

Cerkoryn
Copy link

@Cerkoryn Cerkoryn commented Jun 3, 2025

Background

Issue ouroboros-network#4051 raised concerns that the original Praos implementation used the raw VRF value from the block header instead of the range‑extended leader VRF value. The issue notes:

In the `TPraos` protocol (used prior to the Vasil HF), `csvLeaderVRF` was the leader VRF value. In the `Praos` protocol, however, `csvLeaderVRF` is being set to the single VRF value in the block header (prior to the range extension).

**This removes a small advantage that small pools previously enjoyed.** Small pools are more likely to win this tie breaker … Using the VRF value before the range extension is applied removes this small advantage.

The change to use the raw VRF value took away the small‑pool advantage that existed when ties were settled with the leader VRF value.

What this PR does

This PR modifies the Praos implementation to once again use the range‑extended leader VRF value for tie‑breaking:

-- Use the leader VRF value derived via range extension.
-- This mirrors the behaviour of 'TPraos', giving a slight
-- advantage to smaller pools in slot battles.
-- See https://github.com/IntersectMBO/ouroboros-network/issues/4051
-- for the discussion around this tie breaker.
pTieBreakVRFValue =
    mkTestOutputVRF
  . bvValue
  . vrfLeaderValue (Proxy @c)
  . hbVrfRes
  . headerBody

Additional imports for vrfLeaderValue, mkTestOutputVRF, and helpers were added at the top of the file:

import Cardano.Crypto.VRF (certifiedOutput, mkTestOutputVRF)
…
import Ouroboros.Consensus.Protocol.Praos.VRF (vrfLeaderValue)
…
import Cardano.Protocol.TPraos.BHeader (BoundedNatural (bvValue))
import Data.Proxy (Proxy (..))

This restores the small‑pool advantage in slot battles by using the leader VRF value, matching the behavior before the change referenced in the original discussion.

Why this matters

This modification appears in conjunction with a new cardano-node release and is not exposed as a parameter. Consequently, it is not straightforward to place the change into a standard Parameter Change Governance Action. Community feedback is needed, but there isn’t a clear venue for it. Even if this alteration is ultimately not accepted, the PR can help spark the discussion about where protocol-level tie‑breaker rules should be governed.

Additional notes

The PR was produced using the latest Codex AI tooling with oversight from @Cerkoryn

Due to CI limitations in the provided environment, cabal test all could not fetch dependencies. Anyone reviewing these changes should run the full test suite locally.

Please have knowledgeable developers audit and validate the change before merging.

This PR aims to reopen community dialogue and ensure that the implications of using the leader VRF value (and the small-pool advantage it provides) are properly debated. This issue was additionally raised on X by EarnCoinPool in this post: https://x.com/earncoinpool/status/1925976197520929235.

Parties that may be relevant to this discussion:
@AndrewWestberg @disassembler @kevinhammond

Copy link
Member

@amesgen amesgen left a comment

Choose a reason for hiding this comment

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

Thanks for opening this, fully agreeing with

Community feedback is needed, but there isn’t a clear venue for it. Even if this alteration is ultimately not accepted, the PR can help spark the discussion about where protocol-level tie‑breaker rules should be governed.

One natural place would be the Consensus Working Group call (next iteration on the 19th of June, see the Intersect Discord). There also is overlap with the Ledger Working Group (eg as the reward scheme falls into their territory).


Some high-level thoughts:

The problem that this change intends to address is to improve the situation of small SPOs, most directly by increasing their expected rewards.

I think the core points to consider are therefore:

  1. Is there agreement that this actually is a problem?

    To a certain degree, we want to discourage small pools, in order to avoid Sybil attacks.

  2. How exactly does this change achieve that goal?

    This requires a quantification of eg how much the expected rewards of a small pool would increase due to this change. Eg calculating how often slot battles happen is straightforward; estimating the frequency height battles requires additional assumptions; a first step could be to take empirical data from eg https://pooltool.io/networkhealth.

  3. Are there alternatives achieving the same goal?

    Concretely, an alternative is to adjust the reward system to favor smaller pools, cf IntersectMBO/ouroboros-network#4051 (comment). This could either involve changes to related protocol parameters (simple case), or require more fundamental changes to the reward system (involved case).

    Another (only half-serious) idea that has been flying around is that we could have an even more drastic tiebreaker: The smaller pool simply always wins the battle. However, this might have undesirable side effects.

    One then needs to judge the tradeoffs of all solutions against each other.

Comment on lines +195 to +200
pTieBreakVRFValue =
mkTestOutputVRF
. bvValue
. vrfLeaderValue (Proxy @c)
. hbVrfRes
. headerBody
Copy link
Member

Choose a reason for hiding this comment

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

For a proof-of-concept implementation, this seems fine; however, for an actual implementation, it makes sense to avoid mkTestOutputVRF and going through Natural.

Also, one needs to add

{-# LANGUAGE ScopedTypeVariables #-}

at the top to get this to compile.

Copy link
Author

Choose a reason for hiding this comment

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

Thanks for your response @amesgen.

One natural place would be the Consensus Working Group call (next iteration on the 19th of June, see the Intersect Discord)

I was not aware of the existence of this working group, but if we are able to get this issue added as a discussion item I'm sure one of us from the SPO Incentives Working Group would be willing to show up and make the case for reverting back to using the L hash for slot battles.

To a certain degree, we want to discourage small pools, in order to avoid Sybil attacks.

I think regarding this and the explanation in @dcoutts comment that pledge was designed to be the limiting factor for both pool splitting and Sybil attacks.

If we can address that separately then we can empower small pools to our hearts' content without having to worry about exploitation by bad actors. Consequently, we have just re-submitted a CIP with simulation research and a built tool to model it that aims to solve exactly this issue.

The PR to merge it into the CIP-repository is here: cardano-foundation/CIPs#1042. CIP Editors will be reviewing it at their next meeting on 10 June.

Copy link
Member

Choose a reason for hiding this comment

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

One natural place would be the Consensus Working Group call (next iteration on the 19th of June, see the Intersect Discord)

I was not aware of the existence of this working group, but if we are able to get this issue added as a discussion item I'm sure one of us from the SPO Incentives Working Group would be willing to show up and make the case for reverting back to using the L hash for slot battles.

Sounds great, added to the agenda (also pinged you(?) on the Intersect Discord), thanks 👍

To a certain degree, we want to discourage small pools, in order to avoid Sybil attacks.

I think regarding this and the explanation in @dcoutts comment that pledge was designed to be the limiting factor for both pool splitting and Sybil attacks.

If we can address that separately then we can empower small pools to our hearts' content without having to worry about exploitation by bad actors. Consequently, we have just re-submitted a CIP with simulation research and a built tool to model it that aims to solve exactly this issue.

The PR to merge it into the CIP-repository is here: cardano-foundation/CIPs#1042. CIP Editors will be reviewing it at their next meeting on 10 June.

Yeah, these general efforts on changing the reward system are definitely closely related and should be studied together. It seems to me that pool splitting is inherently related to Sybil attacks, but it indeed sounds cool if they could be somehow (at least partially) separated.

Also cc @CarlosLopezDeLara

Copy link
Member

Choose a reason for hiding this comment

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

FYI some notes on how much non-orphaned blocks/rewards would change for small/large pools with this change compared to the status quo: https://hackmd.io/hX7q5s8JSKSP-j3525J0bA

Copy link
Author

@Cerkoryn Cerkoryn left a comment

Choose a reason for hiding this comment

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

Added {-# LANGUAGE ScopedTypeVariables #-} so that the code can compile.

@dnadales dnadales moved this to 🚫 Help needed in Consensus Team Backlog Jun 4, 2025
@adrem1
Copy link

adrem1 commented Jun 4, 2025

Quoting @amesgen:

  1. Is there agreement that this actually is a problem?
    To a certain degree, we want to discourage small pools, in order to avoid Sybil attacks.

Could you please elaborate on this concept?
Who wants to discourage small pools?

@amesgen
Copy link
Member

amesgen commented Jun 4, 2025

Quoting @amesgen:

  1. Is there agreement that this actually is a problem?
    To a certain degree, we want to discourage small pools, in order to avoid Sybil attacks.

Could you please elaborate on this concept? Who wants to discourage small pools?

In this context, a "sybil attack" is referring to an attacker creating a huge number of tiny pools, in order to gain some kind of advantage (depending on the context, this could for example be a reduction of networking performance or unbounded ledger state growth). There is broad agreement that such sybil attacks should be disincentivized in some way.

Concretely, the current reward system uses pledging via the $a_0$ parameter, see eg this blog post, which disincentivizes creating lots of small pools (as pledge can not be "shared" across different pools).

Of course, there is no binary decision between "small pools are encouraged" and "small pools are discouraged"; just a degree of how incentivized or disincentivized small pools are. In particular, new pools are usually small, so a pool being small shouldn't be too disincentivized. These tradeoffs are subject to community discussion:

  • This PR is a change that benefits small pool operators, no matter whether they are great new honest pool operators, or an attacker preparing a Sybil attack, so these things need to be weighed against each other.

  • Since Voltaire, protocol parameters like $a_0$ can be changed via on-chain governance.

  • There is work on potential changes to the reward system in CIP-0050, as well as the recent CIP-0050 | Modernization & Additional Research cardano-foundation/CIPs#1042, involving in particular @Cerkoryn.

@snic-csp
Copy link

snic-csp commented Jun 5, 2025

  • or an attacker preparing a Sybil attack

A bad actor preparing a Sybil attack needs more than a bunch of pools, they need a large supply of ada/delegation to make any such attack effective.

@TerminadaPool
Copy link

Quoting @amesgen:

Is there agreement that this actually is a problem?
To a certain degree, we want to discourage small pools, in order to avoid Sybil attacks.

I agree, this is a design feature of Ouroboros rather than a bug. Ouroboros does seek to somewhat discourage small pools to avoid Sybil attacks.

As the operator of a small pool, and the one who first identified the change in 2022 from using "leader VRF" to "block VRF", I can say that I was upset, because prior to that change, my pool was benefiting by winning a high proportion of fork "battles".

But, the Ouroboros design doesn't seek to prefer small pools through advantaging them when settling fork ties. Instead Ouroboros tries to achieve a network of "K" fully saturated pools by incentivising stake to coalesce towards nearly saturated pools competing over fees.

Changing back to using leader VRF to settle ties would create an incentive for pool splitting in order to game that advantage, especially when it is easy to run multiple pools using virtual machines on the same infrastructure. We want to do the opposite of this. We want to encourage pool operators to coalesce their pools.

On the other hand, it is a fairness principle that new entrants should be able to compete against large incumbents. However, there are some factors which were not intended in the Ouroboros design that are currently advantaging large incumbents:

  1. Fixed minPoolCost (currently 170 Ada) restricts new entrants from competing on fees. minPoolCost results in a higher percentage of staking rewards consumed by fees for those staking with small pools. But, the Ouroboros papers don't mention any limits on what pools "must" charge. minPoolCost is not in the Ouroboros papers.

  2. "Sticky stake" gets accumulated over time by large incumbents and it gives these large operators more pricing power because they can split pools and undercut the new entrants with these additional pools. Importantly, this "sticky stake" is inactive and does not contribute to Cardano's resilience against 51% attacks. The Ouroboros papers didn't envisage the existence of inactive stake being rewarded for doing nothing with staking rewards.

  3. Pool splitting advantages large operators through economies of scale. The Ouroboros design also didn't envisage that operators would split pools.

I think it would be better to work on fixing these things which can be viewed as "loop-holes" within the Ouroboros protocol.

I don't like the idea of perverting an aspect of Ouroboros design which was intended to be fair by making it unfair, to the advantage of small pools, as a kind of way to make up for the loop-holes.

@adrem1
Copy link

adrem1 commented Jul 27, 2025

Hi TERM,

some of the points you make below are being evaluated by a Community lead initiative called the Cardano Incentives Working Group, of which OP (@Cerkoryn) is part of. Specifically:

  1. Fixed minPoolCost (currently 170 Ada) restricts new entrants from competing on fees. minPoolCost results in a higher percentage of staking rewards consumed by fees for those staking with small pools. But, the Ouroboros papers don't mention any limits on what pools "must" charge. minPoolCost is not in the Ouroboros papers.

https://incentives.solutions/lower-minpoolcost-to-0/

  1. "Sticky stake" gets accumulated over time by large incumbents and it gives these large operators more pricing power because they can split pools and undercut the new entrants with these additional pools. Importantly, this "sticky stake" is inactive and does not contribute to Cardano's resilience against 51% attacks. The Ouroboros papers didn't envisage the existence of inactive stake being rewarded for doing nothing with staking rewards.

https://incentives.solutions/cps-lost-stake-2/

  1. Pool splitting advantages large operators through economies of scale. The Ouroboros design also didn't envisage that operators would split pools.

https://incentives.solutions/cip-50-rebirth/

I think it would be better to work on fixing these things which can be viewed as "loop-holes" within the Ouroboros protocol.

I don't like the idea of perverting an aspect of Ouroboros design which was intended to be fair by making it unfair, to the advantage of small pools, as a kind of way to make up for the loop-holes.

https://hackmd.io/hX7q5s8JSKSP-j3525J0bA

None of these proposed ideas work in a vacuum, but in concert they would, in our opinion, mitigate some of the concerns you raised above.

Respectfully,

Stef

@TerminadaPool
Copy link

Thanks Stef. I am aware of the ongoing work to correct some of the loop-holes within the current protocol operation. IE:

  • Lower minPoolCost ongoing campaign. I have been publicly campaigning for this to happen on Cardano Forum since 2022.
  • Un-reward "sticky stake" - eg. by expiring it, since it is not fulfilling its side of the staking contract to receive rewards. I have also been publicly campaigning for this on Cardano Forum.
  • Making pledge count more - CIP 50 rebirth. I actually helped Dr Michael Liesenfelt with the initial writing of what eventually became CIP 50.

So, I definitely would like to see the playing field levelled. However, I would like to see this happen by fixing loop-holes rather than creating new ones. This proposal seeks to introduce what I believe is a design flaw, as a way to somehow re-balance the advantages large multi-pool operators are obtaining through exploiting loop-holes. Respectfully, in my opinion, doing so would be a mistake.

General principle argument:

As a general principle it is a bad idea to create a protocol advantage towards new small pools.

Large old pools have invested time to build brand reputation and collect stakers. Even if these old pools don't have as much pledge as some others they still have their reputation and their following of loyal stakers to lose if they behave maliciously. Many have spent years paying network and hardware costs as well as communicating with the community via youtube, Cardano Forum, X/Twitter, etc. to build these pools. They don't want to see this business value destroyed. This is expensive and real "skin in the game".

On the other hand, it is cheap and quick to spin up 10 new small pools with pledge split across them. Hell, I can even rent staking rights for a period of time using "Liquidity bonds".

But, this principled argument is not enough since people won't see past their own pocket books, so here are some examples:

Example unwanted outcomes:

  1. Incentivises pool splitting:

    Let's say I am a whale with 10M Ada and currently run a single pool where I have pledged the entire 10M. If this change is implemented then I will simply take 9M of that pledge and make 9 new pools each with 1M staked. The people staked to my original pool won't care about my reduction in pledge from 10M down to 1M on that pool, and I will retain the sticky stakers anyway because they won't budge. But, now I am better off having 10 small pools rather than 1 big pool because I will win more "fork battles" and will still receive the same number of blocks across my 10 pools as I would have if I had only the one larger pool.

  2. Incentivises increased network delays:

    But, since a small pool will nearly always win "fork battles" with this change then why not cause more fork battles? So to further improve my advantage compared to the rest of the network, I can create an artificial network delay of 1-2 seconds on sending and receiving blocks to/from my 9 small pools. 1 second of delays means that 15% of my blocks will result in "fork battles" and 2 second delays will result in 25% of my blocks causing "fork battles". Since I will win nearly all these fork battles, this is good for me and bad for all the large pool operators. Relatively speaking, my collection of small pools will earn more rewards compared to the average.

  3. Reduction in ownership requirement to "control the chain":

    Cardano boasts that for a malicious actor to "control the chain" requires that actor to own 51% of the Ada supply. But if this change is implemented then this requirement will reduce to something less than 51%.

    The important factor in determining how much Ada I must own to control the chain is not actually the percentage of Ada owned, but rather the ability to make sure that 51% of the blocks that become part of the canonical chain are produced by me. IE: It is the percentage of blocks adopted that is the important metric. So, if I can make the chain have more forks, and make it so that I will win most of these "fork battles", then I won't need 51% of the Ada supply.

    So I can combine the above two attacks along with some spamming of all Cardano relays to increase delays within the network. I go out and rent a bot farm to create enough spam so delays blow out to 2 seconds for everyone. This now means that 25% of all blocks produced will result in "fork battles". I then spin up thousands of small pools each with only a small amount of Ada so that I can win nearly all fork battles. Now I don't require 51% of the Ada supply to control the majority of the blocks in the canonical chain, but rather something significantly less.

  4. ... And, there will be other attack methods, since if this is implemented, the fork battle outcome for small pools becomes predictable. And, it is cheap to create new small pools. (Nb: The 500 Ada deposit when creating a new pool is cheap in the scheme of things, and it is refundable.)

@dcoutts
Copy link
Contributor

dcoutts commented Aug 27, 2025

Thoughts so far:

  1. This is a protocol change, and as such it must have appropriate governance approval. The incentives working group is a good place for general discussion but I would also suggest presenting it to the TSC. It would be straightforward for the working group to get this on the TSC agenda.
  2. I have not yet seen any quantification of the problem or the proposed solution. I think this is a necessary prerequisite for governance approval so that people can evaluate the scale of the problem and the change.
  3. This is not a principled solution to the problem (assuming one agrees that there is a problem). It is a re-introduction of a bug, but seen as a design it is extremely ad-hoc. A proper design would introduce deliberate and tunable bias with a protocol parameter to control the degree of the bias.

From (unpublished) analysis that I have done about slot battles, I think the problem is actually tiny and that the solution does little to address the problem.

That is, the number of slot or height battles is already very small, and thus the number that small pools experience and loose is also very small. And the bias introduced by the "solution" is also slight. Thus I would expect the "solution" to have little effect on the problem.

@amesgen
Copy link
Member

amesgen commented Aug 27, 2025

I have not yet seen any quantification of the problem or the proposed solution. I think this is a necessary prerequisite for governance approval so that people can evaluate the scale of the problem and the change.

FTR I have written up how much the expected rewards would change due to this (only taking a look at slot battles; but height battles are much more rare empirically, so it shouldn't change the picture too much): #1548 (comment)

TL;DR the impact is rather small:

  • The smallest 2560 pools (with $43\,\%$ combined stake) benefit from this change.
  • The largest 205 pools (with $57\,\%$ combined stake) lose out from this change.
  • The smallest pool that loses out from this change has $0.185\,\%$ stake.
  • Largest relative benefit from this change: $+2.6\,\%$
  • Largest relative loss from this change: $-1.4\,\%$

There might be some more statistical things to compare, like by how much less the rewards/performance of small pools fluctuate due to this change (which might actually be more relevant for small SPOs), but it is not clear to me how to best do that (eg the coefficient of variation doesn't decrease much).


Also linking the slides and the recording from the Consensus Working Group channel on Discord as well as the e-mail to the TSC here as well, which talk about this and other things:

@dcoutts
Copy link
Contributor

dcoutts commented Aug 27, 2025

@amesgen that's great! So do you think it's a fair headline to say that best case, there's a 2.6% financial benefit to some of the smaller pools?

@dcoutts
Copy link
Contributor

dcoutts commented Aug 27, 2025

Summary from today's TSC meeting:

  • Our advice is to write a CPS to gain social consensus on the nature of the problem. i.e. do we want bias and if so how much? How should that bias be distributed.
  • Look for a design. This should be a coherent design, probably one with a protocol parameter to control the degree of bias. It would (almost certainly) not look anything like the previous bug/design that relied on slot battles.

@amesgen
Copy link
Member

amesgen commented Aug 27, 2025

@amesgen that's great! So do you think it's a fair headline to say that best case, there's a 2.6% financial benefit to some of the smaller pools?

Yes, while emphasizing that this is about mean rewards (so measured over a sufficiently long period of time), and with the caveat that the benefit would increase if height battles became much more frequent. (Not the most elegant headline then 😿)


Also (see https://hackmd.io/hX7q5s8JSKSP-j3525J0bA), there are simple generic bounds (for slot battles) for how much the mean rewards can change simply by changing the bias of tiebreaking, namely by assuming the extreme case that a pool previously lost every single slot battle, but it is now winning every single slot battle (or vice versa). In that case, when $r$ is the ratio between your old and new mean rewards, we have $1-f \le r \le 1/(1-f)$ where $f=1/20$ is the active slot coefficient, so $95\,\% \le r \le 105.263\,\%$.

So even assuming we introduce maximum bias (in either direction) to the tiebreaker, as long as height battles don't become much more frequent, the mean rewards can't improve by more than $5.263 \,\%$ for any pool.

@Cerkoryn
Copy link
Author

  • Our advice is to write a CPS to gain social consensus on the nature of the problem. i.e. do we want bias and if so how much? How should that bias be distributed.
  • Look for a design. This should be a coherent design, probably one with a protocol parameter to control the degree of bias. It would (almost certainly) not look anything like the previous bug/design that relied on slot battles.

@dcoutts I think the problem itself could be summarized by saying that a small pool that makes less than one block per epoch is disproportionally affected by losing the dice roll of a slot/height battle compared to a large pool who makes many blocks. From a broad point of view, the slot/height battles are not frequent enough to be a big deal (see @amesgen's HackMD post), but from a the small SPO's perspective they are very much a big deal.

Perhaps a more meta-problem I've heard from SPOs is that the ledger previously used the L hash and they became accustomed to it, and then it was changed to the B hash seemingly without warning (i.e., no CPS for social consensus, no CIP, no governance, etc.).

I think a CIP that introduces a new protocol parameter to control the degree of bias sounds interesting, but coming up with such a design is probably beyond the technical ability and time commitment of our all-volunteer Incentives Working Group. Our intent is to see if we could simply switch back to the way things were done before.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: 🚫 Help needed
Development

Successfully merging this pull request may close these issues.

6 participants