Heads-up to bakers and builders: A new delegation calculation tool is coming soon to Octez

TL;DR A new calculation tool is being integrated into Octez to help bakers and baking tooling builders understand better how much each of their delegators contributes to their consensus rights. The output of this tool will be available as an Octez node RPC endpoint, enabling more transparency and insight into baking power distribution — without aiming to become a full delegation rewards distribution system.

We are sharing this plan today, to give a heads up to Tezos bakers and builders. Do not hesitate also to provide feedback on the proposed design, and suggestions on how to improve this new feature.

Context

The adoption of the Paris protocol upgrade changed how the Tezos protocol estimates delegators’ contributions towards their bakers’ baking power, and consequently the share of rewards they would be eventually paid by their baker. Paris deprecated the previous approach based on aleatory stake snapshots by a continuous mechanism which determines the minimal delegated balance of a baker in the cycle.

The Quebec protocol refined this mechanism further by amending the granularity of the computation of the minimal delegated balance and improving the information available via RPC endpoints. This was necessary to address reported frictions in downstream infrastructure, like indexer and Tezos reward distribution tools.

To assist bakers and tool developers further, and remove the burden of computing delegator shares closer to the Tezos protocol, core engineering teams are planning to introduce a new RPC endpoint which will easily report all contributions by delegators to their baker’s delegated balance in a given cycle.

What This Tool Does

  • For a given cycle and baker, it breaks down the computation of the baking power arising from delegated tez in that cycle.
  • Crucially it provides the share of each individual delegator and the baker’s own towards this total.
  • It helps quantify the real impact of each delegator on baking power and would allow for a leaner computation of delegator rewards.

:stop_sign: This tool is not a full reward calculator – its purpose is to provide more clear information on the different contributions to baking rights from delegation.

Please see Baking Power in Octez for further reference.

How It Works

The new tooling will be integrated into the Octez suite, and can be queried via a new dedicated Octez node RPC endpoint.

RPC path

/chains/<chain>/delegators_contribution/<reward_cycle>/<baker_pkh>

edit: The endpoint’s path has been updated to reflect its current implementation on tezos/tezos master branch.

Parameters

  • reward_cycle: The target cycle for which to calculate the share of baking power from delegated tez.
  • baker_pkh: The public key hash of the baking (or manager) key for the baker whose shares are being calculated.

JSON Output

The RPC endpoint outputs values given in weighted mutez.

Staked and delegated tez have different weights in the computation of baking power:

  • Staked tez have a weight of 1. That is, they contribute to baking power at their nominal value.
  • Delegated tez have a weight of 1/3, meaning they contribute a third of their nominal value.

The proposed JSON output has the following shape:

{ "total_baking_power" :  96_000_000_000 ,
  "total_baking_power_from_delegation" :  6_000_000_000 ,
  "delegators_share" :[
	"tz1a…." : 6000 ,
	"tz1b…." : 4301 ,
	"KT1b…." : 201 ,
	...
],
  "self_delegated": 8000,
  "overstaking_share": 4800,
  "untracked_unstake_requests": 5000,
  "overdelegation" : 150, 
}

where:

  • total_baking_power: The baker’s total baking power in the queried cycle.
  • total_baking_power_from_delegation: The portion of the baker’s baking power that comes specifically from delegated tez, with:
total_baking_power_from_delegation =
  delegators_share + overstaking_share + untracked_unstake_requests - overdelegation`
  • delegators_share: Maps delegators to their respective contributions towards their baker’s total baking power from delegation. It includes delegated spendable tez, frozen rollup bonds, unstaked tez, and other sources - see the docs for its complete definition.
  • self_delegated: The baker’s own contribution to its delegated baking power.
  • overstaking_share: The total share of the baking power from delegation that originates from overstaked tez.
  • untracked_unstake_requests: The aggregated contribution from unfinalized unstake requests from delegators that have changed their delegation to a new baker and that are still counted towards the baker’s baking power.
  • overdelegation: The total delegation excess which is not taken into account for the computation of baking power in the case the baker is overdelegated.

Requirements & Best Practices

As hinted by the path of the proposed endpoint, this is not a “protocol” RPC endpoint, but rather a shell one. This is because of the additional business logic required to serve these requests, which takes place outside the Tezos protocol.

  • Given its computational cost, the Octez node’s RPC server should be configured to be run as a separate process, when using the proposed endpoint.
  • It should not be exposed publicly by Octez nodes.
7 Likes

TL;DR: We already have a robust solution (protocol-rewards). It may be more productive to allocate resources elsewhere.

Hi,

while I appreciate the potential benefits of integrating such a tool directly into the core, we currently have a solution in place—protocol-rewards (PR)—that already meets most of your stated requirements and can be easily adjusted for the rest.

PR was specifically designed to integrate smoothly with TzKT endpoints and provides several key features:

  • Power distribution analytics for all bakers, stakers, and delegators
  • Option to operate PR specifically for a single baker
  • Rolling storage, persisting only the last N cycles for efficient querying
  • Optimized performance, likely faster than yours in ocaml, unless the latest OCaml multithreading enhancements are utilized

PR has been successfully powering tezpay since the Paris upgrade, and we’ve consistently maintained and supported it. Given this, the proposed integration might largely duplicate existing functionality, potentially diverting resources that could be better utilized addressing other community requests or enhancements.

One particular improvement that would significantly help us is an RPC endpoint for querying dangling unstake requests. Currently, we’re reliant on TzKT for this data, and while your proposal mentions untracked_unstake_requests - it would be particularly beneficial to identify specifically which delegators own these outstanding requests rather than just viewing aggregate totals.

NOTE: If desired, we can transfer the project (PR) to core teams for them to take over.

Thank you again for your efforts and consideration.

Best regards,
Val

1 Like

One additional note, as this seems to be misunderstood: We specifically need identified unstake requests to distribute rewards accurately. If the tool is implemented as currently proposed and integrated by payout distributors, it would lead to incorrect payouts.

Consider this scenario: If you delegate to another baker, your balance is automatically unstaked, making you eligible for delegation rewards from your unstaked balance with the original baker, and from your remaining balance with the new baker. With the proposed solution, delegators/stakers are going to lose rewards from their unstaked balances.

Interesting stuff. Look forward to testing it out. Available now with Octez v22, or is that later? Agree with @Val comments. Hopefully this is not a reinvention of an existing wheel

2 Likes

Thanks @Val / @cardsfan7189 for your feedback.

The main goal of this new tool in Octez is to provide fine-grained insight into the computation of delegation rights which is not currently supported at protocol level.

The rationale for integrating it as a part of Octez is not to replace existing ecosystem tooling, but rather to streamline their development. Keeping the new tooling closer to the implementation of Tezos protocols would allow for implementing changes in this tool seamlessly and transparently for its users, as the Tezos protocol evolves.

As for providing a fine-grained breakdown of untracked unstaked requests, we understand that this is still an issue for the maintenance of delegation rewards distribution tooling. We plan to address this issue in future versions of the delegator rights calculation tool.

2 Likes

Shell & plugin: delegators contribution RPC (!17406) · Merge requests · Tezos / tezos · GitLab has been merged into master. Will it be backported to v22?

I’ve compiled from master and tried it out. There’s an error in RPC path in the OP. The correct path is:

/chains/<chain>/delegators_contribution/<cycle>/<baker_pkh>

For example:

 wget -q -O - http://localhost:8732/chains/main/delegators_contribution/849/tz1R4PuhxUxBBZhfLJDx2nNjbr7WorAPX1oC | jq

Returns

{
  "own_delegated": "1506693803",
  "external_delegators": [
    {
      "delegator_contract_hash": "KT1UZqFyHjXnk2WTRKUPx4NobFzq8zQj7PNT",
      "contribution": "5783923764"
    },
    {
      "delegator_contract_hash": "KT1EG8EhvWNAuKg9D7DVi8FHBLA5rLYET6Vu",
      "contribution": "0"
    },
    {
      "delegator_contract_hash": "tz2Tn3EQzDvmZQPCvY53bFbRQYs9UKWf7Fhf",
      "contribution": "69780129"
    },
    {
      "delegator_contract_hash": "tz2FqjFrNYJLG94gsjaTzNLwRRWpD6mp2muK",
      "contribution": "132601694"
    },
    {
      "delegator_contract_hash": "tz2Ce8he6Pt3FtCrjKZKw3TCHk9z1zVHEEkb",
      "contribution": "35646151"
    },
    {
      "delegator_contract_hash": "tz29bdSw3hyAudtXNhVryK3G3DGYd1PpAF3k",
      "contribution": "425390451"
    },
    {
      "delegator_contract_hash": "tz28cSXsjbX7d1z9od64NFq1DEkC5gCuwQpM",
      "contribution": "15942407"
    },
    {
      "delegator_contract_hash": "tz1ixDpiEDq64PzLuBb19DCrCwoiP7jKuz8G",
      "contribution": "9312923313"
    },
    {
      "delegator_contract_hash": "tz1iQnPygVXs2szGNQCj9bUX2PpxHZwswRrZ",
      "contribution": "1785852360"
    },
    {
      "delegator_contract_hash": "tz1i18msse7fJxLcSp1NKLrgCnKjE8jGChNc",
      "contribution": "21390759"
    },
    {
      "delegator_contract_hash": "tz1hVTU5wkyAfHqBSeF7WALF3ynDFVcpq2gp",
      "contribution": "15559588"
    },
    {
      "delegator_contract_hash": "tz1e9RDh3ZCE3RPch8cqM6X7ujwKsxzMJ7vV",
      "contribution": "2138035001690"
    },
    {
      "delegator_contract_hash": "tz1d6bxmXXJ6xba3KT7zCnVmTHTYW7oxSbBe",
      "contribution": "941091292869"
    },
    {
      "delegator_contract_hash": "tz1bxFQj8cHj47C5jPUovGovgzA2p7S33g3d",
      "contribution": "10112852"
    },
    {
      "delegator_contract_hash": "tz1b8rA1PXDd38pF2bzp4Kk3Xnb89KEsewoE",
      "contribution": "8410995"
    },
    {
      "delegator_contract_hash": "tz1ajTC3KtMH3uMikbCNoMoa1UNxfwnvSqwp",
      "contribution": "137532547"
    },
    {
      "delegator_contract_hash": "tz1aD413LAu8Hn5KHt2bPtkkqm8wQLnk4LTG",
      "contribution": "2157000653"
    },
    {
      "delegator_contract_hash": "tz1a4LGBsDBPf5MmUaS7qwC9sCUGq9rNZoBb",
      "contribution": "872685"
    },
    {
      "delegator_contract_hash": "tz1ZkPDuWc6SK4trkn5s8djkekzxPrR4DM1b",
      "contribution": "99256"
    },
    {
      "delegator_contract_hash": "tz1ZUSShh5A7yXU4JBPYb5ZnbcDUt13bzXXT",
      "contribution": "16045306762"
    },
    {
      "delegator_contract_hash": "tz1YRQUcx4b4b9DvEFoFH1XT7AiyQYhcZTFC",
      "contribution": "273353200"
    },
    {
      "delegator_contract_hash": "tz1XvxoLDhMzaeGjPghoo99ah1ADuetYTiT1",
      "contribution": "17532061"
    },
    {
      "delegator_contract_hash": "tz1XvFTUpeSrSvaUqnXSE8KoJaymvg8qrU46",
      "contribution": "370710397"
    },
    {
      "delegator_contract_hash": "tz1XijnU5PGwbxqVDawpapfsAQcnZtsAuWpp",
      "contribution": "10545634"
    },
    {
      "delegator_contract_hash": "tz1XLLc5NQk65d3beJ3ih1NWMt196Ae39WzJ",
      "contribution": "2714214"
    },
    {
      "delegator_contract_hash": "tz1WqCKeqEE1URXcmRWBNYEGDy4g1o7dp99o",
      "contribution": "23483072"
    },
    {
      "delegator_contract_hash": "tz1Wpf5M5mjLPTM8LDRbBpxUKhornMuKRA61",
      "contribution": "36565720"
    },
    {
      "delegator_contract_hash": "tz1WSYRrJT7RKVgYR1byVe7ey9G7yAFbbNBa",
      "contribution": "5777538808"
    },
    {
      "delegator_contract_hash": "tz1Vwj1JLwcuvsziJUbAFFE1KorVip8wLTBm",
      "contribution": "408638"
    },
    {
      "delegator_contract_hash": "tz1VJtMgyT73SAh5FdECpLnuGaoCGKWQjqZV",
      "contribution": "214997888"
    },
    {
      "delegator_contract_hash": "tz1V7TmHS54EsseE52gg4yfZqohFEMyyD3yC",
      "contribution": "8989423"
    },
    {
      "delegator_contract_hash": "tz1V77RHr339mXS46zYXHfGVcaxfRxdYmcHc",
      "contribution": "10672104"
    },
    {
      "delegator_contract_hash": "tz1V3mUVNmfeeZUEN8358i8bjD9rVnEbK7nc",
      "contribution": "604484417"
    },
    {
      "delegator_contract_hash": "tz1ULWNhrBbH6MeG6Ds9C7fSZVwizDkTeiDJ",
      "contribution": "704689979"
    },
    {
      "delegator_contract_hash": "tz1RmmUixjiWcXWpJL7FoghPJpwwJJVGrBnK",
      "contribution": "23046602"
    },
    {
      "delegator_contract_hash": "tz1RZNHQpJSUBDYXi4uKCUCAa2XGwM7GoLry",
      "contribution": "5223013"
    },
    {
      "delegator_contract_hash": "tz1QPLQck5TYBDHQNJknJAzsK3KZH234Qhjj",
      "contribution": "242809367219"
    },
    {
      "delegator_contract_hash": "tz1QM4G7jgtEGwQpT3NwMiF4zbvc449VCR1V",
      "contribution": "5083854673"
    },
    {
      "delegator_contract_hash": "tz1QC4TqFSAEdx7W1GVWPEY5tpNj44J9AL1K",
      "contribution": "29350229713"
    },
    {
      "delegator_contract_hash": "tz1Q77mfTzUznCNzFnCvbHne4b4qU5aQoxrf",
      "contribution": "2517656675"
    },
    {
      "delegator_contract_hash": "tz1PyY3ieSd6QWWe32LFuiiiTaHQzwHWarh9",
      "contribution": "357163823"
    },
    {
      "delegator_contract_hash": "tz1NYYpWmbsfbnHVt5SKErVjVwmHJwa1fWQS",
      "contribution": "17449300"
    },
    {
      "delegator_contract_hash": "tz1MerpSa4h4nvt1bZhFPzCFQnrw9keAQNXy",
      "contribution": "121039005"
    },
    {
      "delegator_contract_hash": "tz1LD2Aicged9Naoz2WwCGmJZwg1j6ULk1BD",
      "contribution": "16725997"
    }
  ],
  "former_delegators_unstake_requests": "0",
  "overstaked": "0",
  "total_delegated_including_overdelegated": "3404949776303",
  "total_delegated_after_limits": "3404949776303",
  "overdelegated": "0"
}

Querying the current cycle, 848 at the time of writing, returns an error.

Here’s what appears in the nodes logs.

server (16) resto_callback accepted connection: request
/chains/main/delegators_contribution/848/tz1R4PuhxUxBBZhfLJDx2nNjbr7WorAPX1oC
2025-04-04T20:57:53.945-00:00 [rpc_server.rpc_http_event_info] [pid:55134][resto]
server (16) response code:
500
2025-04-04T20:57:53.945-00:00 [rpc_server.rpc_http_event_info] [pid:55134][resto]
server (16) error: response body:
[{"kind":"temporary","id":"delegators_contribution.cycle_too_far_in_past"}]

The client however doesn’t get the error message other than a 500 occurred with wget.

Connecting to localhost:8732... connected.
HTTP request sent, awaiting response... 500 Internal Server Error
2025-04-04 17:04:18 ERROR 500: Internal Server Error.

octez-client however does provide more details.

octez-client --endpoint http://localhost:8732 rpc get /chains/main/delegators_contribution/848/tz1R4PuhxUxBBZhfLJDx2nNjbr7WorAPX1oC
Fatal error:
  Command failed: Unregistered error:
                    { "kind": "temporary",
                      "id": "delegators_contribution.cycle_too_far_in_past" }

Thanks a lot for testing this RPC and for your detailed feedback! :folded_hands:

You’re absolutely right — the RPC path mentioned in the original post is incorrect. The correct one is indeed:

/chains/<chain>/delegators_contribution/<cycle>/<baker_pkh>

We’ll look into updating the original post to reflect this correction. I don’t personally have the rights to edit it, so the fix will likely land later.

Out of curiosity, could you share a bit more about your node setup? This RPC requires access to the contexts of all blocks used in the computation, which means it must be run on an archive node or a full/rolling node with enough store history. If you ran it on a node that was started from a fresh snapshot, that might explain the “cycle too far in the past” error — it likely refers to a cycle that’s beyond the node’s available context history.

That said, we’ll also investigate why the error wasn’t displayed more clearly and work on improving it. This RPC is still experimental and hasn’t been included in any Octez release yet — but we’re aiming to have it included as son as possible.

Thanks again for testing and reporting!

1 Like

The error not being returned with wget seemed weird to me because it’s being returned by octez-client so I investigated. It turns out that wget doesn’t show the body by default on errors, it needs the --content-on-error flag. The following works fine.

wget --content-on-error -q -O - http://localhost:8732/chains/main/delegators_contribution/848/tz1R4PuhxUxBBZhfLJDx2nNjbr7WorAPX1oC

curl works without any flags.

curl http://localhost:8732/chains/main/delegators_contribution/850/tz1R4PuhxUxBBZhfLJDx2nNjbr7WorAPX1oC

I’m running a full node and my last savepoint is cycle 846, however, I was running v21 and v22 until yesterday when I upgraded to master so that might have something to do with it. Here’s my savepoint.

{"block_hash":"BLLVya4jqdM5C8p5P1UyeE9UFqd5B7tbf7QbWDJAHBWSG1ZrjGo","level":8398850}

Cycle 849 has just started and I can now query cycles 849, 850, 851 without errors. Anything before or after these cycles returns a 500. On a side note, a 404 would be more appropriate for errors such as cycle_too_far_in_future and cycle_too_far_in_past

Thanks @RichAyotte for pointing this out – we’ve edited the OP to reflect the updated path

2 Likes

Hi @RichAyotte
Thank you very much for all this feedback. It will undoubtedly help us improve the tool!
Just one clarification, which we’ve neglected to mention until now - apologies: everything we’ve described, and everything you’ve identified, applies to version 22.0 of Octez.
The corrections and improvements we’ll be making will therefore apply to future versions. Of course, we’ll keep you informed!

2 Likes

@germanD @VincentPoulain

While I understand the reasoning behind integrating tools more closely into the core and providing these features at the protocol level, that wasn’t the aspect I found problematic in this case.

The real issue is that we already have an existing, working, and—at this point, I’d even say—battle-tested solution that offers all these features. Meanwhile, there are features people have been requesting for ages, which should be straightforward to develop and test, such as redirecting delegation rewards to a secondary wallet.

Given the current state, the tool you’ve proposed could wait, especially when there are unresolved issues impacting daily operations. And that’s the real concern, in my opinion.