Skip to content

SIMD-0123: Block Revenue Distribution #123

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Jun 9, 2025

Conversation

jstarry
Copy link
Contributor

@jstarry jstarry commented Mar 10, 2024

Delegated stake directly increases the number of blocks that a validator is allocated in an epoch leader schedule but the core protocol doesn't support diverting any of that extra revenue to stake delegators. This proposal introduces a way to set a commission for validator collected block fees and tips and then have the rest of the fees distributed to delegated stake accounts.

@jstarry jstarry force-pushed the block-fee-distribution branch from 72b12eb to 0131156 Compare March 10, 2024 08:21
@jstarry
Copy link
Contributor Author

jstarry commented Mar 10, 2024

cc @buffalu @t-nelson, thoughts on this direction?

It's a little difficult to work around the fact that nodes can have multiple vote accounts technically and that vote accounts can change node ids at will.

@diman-io
Copy link

diman-io commented Mar 10, 2024

Hello, I'm glad to see you looking in this direction.

I wrote my draft on this subject, see SIMD 119, but this one is undoubtedly superior.

I want to highlight that block fees are not the only amounts to be distributed. Validators collaborate with RPC pools, extract MEV from their blocks, and aim to compensate their stakers for the validators' downtime, among other things.
Therefore, it would be beneficial to have the ability to replenish a 'treasury' (for lack of a better term), which will be distributed among stakers.

Again, this would serve as a unified point for monitoring various dashboard sites (and stake pools) for validators' APY. Currently, the focus is solely on the commission percentage. However, as the methods of rewarding stakers evolve, I believe everyone will begin to operate with actual amounts. Thus, a straightforward and comprehensible algorithm for obtaining these data on-chain is essential.

@jstarry
Copy link
Contributor Author

jstarry commented Mar 10, 2024

Thanks for chiming in @diman-io! I'm imagining that most fees including MEV tips will get accumulated into a single fee collection account for now but I'm interested to hear if there are use cases that require more flexibility. Looks like #109 will provide a convenient way to collect different types of fees into that account. Maybe it makes sense to track different types of fees/tips separately so that they can use different distribution methods but I think I would prefer to start with a simple solution that could be made more configurable in the future.

Can you also elaborate more on why using commission might not be flexible enough?

@diman-io
Copy link

#109 is limited in this respect: its essence is to obtain the current leader's dependent account, otherwise, the goal cannot be achieved: the leader is not known in advance, the account must be locked for writing, potentially this account is needed by all block transactions (except for vote transactions), which blocks parallelism - in general, all this cannot be solved in any other way.
And the main thing here is that this instruction is tightly linked to this transaction, its success, and the leader.

Why commissions are not enough. Validators can attract borrowed stake, compensating the loan fees from the block fee. Thus, the percentage from the block fee cannot be the same for all stakers (or it will add many restrictions).

About fee types. Yes, I've also thought about this for a long time. That's why in 119, I proposed several treasuries with different percentages. This adds flexibility in general. Is this necessary? I don't have a definitive answer. I don't think this will allow dashboards to track such revenues because if we move away from hardcoded typing and just allow validators to create multiple treasuries for one epoch, then for typed tracking to work, dashboards will have to know which treasury is of what type. Besides a textual description inside, I think nothing else can be invented. This rather gives validators the opportunity to keep their accounting on-chain, nothing more. On the other hand, it does not accuse the validator of anything, and he can still use off-chain calculation and himself fund the treasuries for the total amount to be distributed.

After much contemplation, I've concluded that all this breaks down into two parts:

  1. Accumulation of additional amounts
  2. Distribution of these amounts among stakers

Part 1) is strongly associated with business processes, financial schemes within the validator's business, so it's hard to program all variants.

But part 2) is clear and, as it seems to me, there are no disagreements among everyone about it.

Moreover, part 2) immediately allows all dashboard sites to see the real profitability of the validator for stakers (i.e., the element that is very important for validators in their competitive fight for stakers)

Returning to 109, honestly, I would go a different way: I would provide for the vote account 4 accounts: an account for paying for voting, an account for collecting base fees, an account for collecting priority fees, and an account for collecting tips (although personally, I don't like this name, I would prefer success fee or something like that).

And then I would leave it up to the validator's discretion to transfer these fees into treasuries for distribution by the program from part 2).

This will give flexibility to the validator in managing these amounts.
And put them on par with other amounts that he wants to distribute among his stakers.

The only issue that exists for me here is that the transfer might not occur in the current epoch, but in the next one. This bothers me from the standpoint of an ideal world scenario. On the other hand, looking at it as a business and in terms of attracting/retaining stake, transferring in the next epoch for the current one (meaning the staker will receive the amounts one epoch later), will retain stakers (because they will not receive additional amounts for the deactivation epoch - these accruals will happen after). So, overall from a business perspective, this is not a problem. And the validator is able to minimize it in the last few blocks of the epoch.

I hope I was able to answer your questions. Structured presentation is not my strongest skill.

@diman-io
Copy link

diman-io commented Mar 10, 2024

So, speaking about 109, I'm more inclined towards some analogy of the ComputeBudgetProgram, but the fee collection would only occur if the transaction is successful.
If such amounts are to be allocated to a separate account, then it logically makes sense to do this for priority fees as well. That is, to do this uniformly for all types of fees.
The same applies to the distribution among stakers. Here, I lean towards not distributing automatically because it imposes restrictions on the validator's business on one hand, and on the other, it simply moves this to an off-chain level (the emergence of such solutions is just a matter of time).

UPD. I'm not a proponent of 109 at all. In my opinion, validators will eventually concentrate MEV extraction in their own hands.

@t-nelson
Copy link
Contributor

see #109

@jstarry
Copy link
Contributor Author

jstarry commented Mar 12, 2024

see #109

I did, what's your point? Did you even read this SIMD to know how it's different from #109?

@t-nelson
Copy link
Contributor

see #109

I did, what's your point? Did you even read this SIMD to know how it's different from #109?

in the discussion of #109, we come to the conclusion that we can basically have arbitrary, leader-defined distributions by implementing two much simpler things.

  1. a syscall/instruction that credits the leader's collector account
  2. allow for vote accounts to specify a collector account independent from the current authorized voter or w/e today.

with these two things, a validator operators can set their collector to a program-controlled account and define distribution in any way they please. this creates a new competitive opportunity

@jstarry
Copy link
Contributor Author

jstarry commented Mar 12, 2024

Great, my understanding was that #109 aims to solve the first simple thing (adding the syscall or instruction to credit the leader's collector account) so I think we're on the same page for that part.

This SIMD aims to tackle the distribution part by allowing validators to create an independent collector account. I'm hopeful that we can have a discussion here about how to implement this in a flexible way without adding too much complexity. But as I mentioned above, there's a sticking point on using the vote account as you suggested because there's technically a one-to-many relationship of validator node id accounts to the vote account.

Currently the collector account for a leader's bank comes from the node id, not the authorized voter key. When calculating the leader schedule we accumulate all the delegated stake for vote accounts and then accumulate all the vote stake according to each vote account's node id.

Since we can't map from node id to a unique vote account, we can't lookup a validator defined collector account saved in vote state. That's why I created this proposal to allow validators to collect fees into a custom collector account which is derived from their node id. This proposal defines an opinionated distribution mechanism which piggy backs on stake reward distribution to distribute fees to delegated stakers.

@t-nelson
Copy link
Contributor

my contention is that the distribution mechanism need not be fixed by, nor imposed upon the protocol.

Since we can't map from node id to a unique vote account

what prevents this?

@diman-io
Copy link

diman-io commented Mar 12, 2024

Currently the collector account for a leader's bank comes from the node id, not the authorized voter key.

Is that so? I mean, I assume that this is exactly how it's implemented in the code of the validator creating the block (because before this, the right to create a block is checked under other conditions).
I always thought it was the validator identity, not the authorized voter. And I always believed that this public key is also used when validating the block (that it's to this key that the fees go in rewards). In other words, there isn't currently an easy way to change the fee collector account.

UPD. I think you meant not the node id as such (which is broadcast in gossip). Regarding validator identity/authorized voter: I can look into this myself, there's no need to spend time on explanations.

@diman-io
Copy link

what prevents this?

I assume that there might exist two vote accounts with the same validator identity/authorized voter.

But I really like the idea of a separate instruction/syscall.

@t-nelson
Copy link
Contributor

there was more discussion around simd 109 alternatives on discord. i think there was some discussion on the topic prior to 109 being created as well, but i can't seem to find it at the moment. cc/ @buffalu

@jstarry
Copy link
Contributor Author

jstarry commented Mar 12, 2024

my contention is that the distribution mechanism need not be fixed by, nor imposed upon the protocol.

Ok, understood. Seems like most people are in agreement so I'll revise that part. I think it's still useful to allow fees to be distributed to stakers if desired but that might be better suited for an amendment.

Since we can't map from node id to a unique vote account

what prevents this?

I've said multiple times now...

But as I mentioned above, there's a sticking point on using the vote account as you suggested because there's technically a one-to-many relationship of validator node id accounts to the vote account.

The protocol allows multiple vote accounts to set their node keys to the same validator node id.

@michaelh-laine
Copy link

Would it make sense to rethink the linking of leader to node identity and rather make it linked to the vote account? The right to produce a block is conveyed directly by the active stake of the vote account. Block rewards could accrue through the epoch in a "suspense account" and be distributed with staking rewards, with a singular commission applied (let's also support non-integer commission values while we're at it?)? This also accomplishes the distribution of block fees as staked SOL with compounding and possibly helps economic security in that a leader who stuffs their own blocks won't immediately receive back their full priority fee (if SIMD-0096 passed) and half the base fee, but rather has to wait until epoch N+2 (given stake cooldown)

@jstarry
Copy link
Contributor Author

jstarry commented May 9, 2024

Would it make sense to rethink the linking of leader to node identity and rather make it linked to the vote account? The right to produce a block is conveyed directly by the active stake of the vote account.

Yeah, definitely worth exploring.

@cyptofan
Copy link

Hey guys. What's the current status of this development?

@michaelh-laine
Copy link

Just thinking about this and reading through the comments above, I'm thinking about the actual distribution mechanism and the impact this would have on the network.

With the number of stake accounts already in existence, adding another process that distribute rewards to all of these would only exacerbate the current issues.

In this regard would it be sensible to tie the distribution together, i.e. collect fees (as described above, in a collector account) and distribute at the same time (in the same process/block) as the inflation rewards? The share of distribution (i.e. commission) can be different, which only alters the amount debited/credited, but it means no additional debits or credits to any accounts (though it may be desirable to have them split for accounting purposes, but still within the same block).

The only in-protocol revenue, consistent among all validators, are block fees and inflationary rewards, so I think MEV, side-deals etc should be outside of the scope of this proposal, though can be tacitly included if the collector account can receive arbitrary credits that are subject to the same distribution formula:

  1. Validators can set two commission values: staking rewards and block rewards (or maybe even just one), this ideally should happen in the vote account, i.e. the newly added commission value lives in the same place and has the same treatment as regular commission, also an opportunity to alter them both to allow decimals.
  2. Intra-epoch block rewards are deposited into the collector account (can be a PDA derived from node identity and seed or something)
  3. Anyone can make arbitrary additional credits to the collector account (i.e. validator deposits revenue from a side deal)
  4. When rewards distribution occurs the commission is applied to the collector account funds (commission paid to vote account) and balance included with rewards paid into stake accounts

This also ensures compounding of rewards as they are distributed as activated stake

The mapping of identity to vote account may still be problematic, especially where a validator changes their authorized voter, but this could be fixed within the same scope, possibly even changing the leader schedule to link to vote accounts (this actually feels like it should require its own SIMD).

This proposal has been stale for some time, I'd like to see how we can revive this and move it forward, what are the blockers right now, is it just uncertainty over best implementation or some sort of hard blocker like inability to reliably link identity to vote account?

@jstarry
Copy link
Contributor Author

jstarry commented Aug 16, 2024

@Benhawkins18 and I just had a discussion about this today FYI and we will be collaborating on determining how to best distribute block fees to stakers. This goal will mostly likely be split into multiple SIMDs to cover things like setting up collector accounts and commission rates, constraining validator ids to have a single vote account, and modifying the inflation stake reward distribution mechanism to support distributing collected fees. @michaelh-laine your latest comment matches our thinking quite closely, thanks for weighing in.

- validator fee program: New core program which supports diverting a portion of
block fees to stake delegators

- validator fee account: New account type which supports setting a commission

Choose a reason for hiding this comment

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

Wdyt about having a separate SIMD just for this piece? This on its own is a valuable feature

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yup, was already writing one up, here's a draft that you can check out. Would appreciate feedback from you and @buffalu. This SIMD now just focuses on 1) where to send commission from different revenue sources and 2) how to collect and distribute post-commission revenue to stake delegators

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oops SIMD draft here: #185

@jstarry jstarry changed the title SIMD-0123: Block Fee Distribution SIMD-0123: Block Revenue Distribution Oct 17, 2024
@jstarry
Copy link
Contributor Author

jstarry commented Oct 17, 2024

Long awaited update on this SIMD..

This SIMD now focuses on 1) how to set a commission rate for different revenue sources and 2) how to collect and distribute post-commission revenue to stakers via validator specific stake rewards pool accounts.

There are a few prerequisite SIMDs...

  1. SIMD-0180 which migrates the leader schedule from using validator identity keys to using validator vote account pubkeys. This allows blocks to be directly tied to a vote account which will store commission rates and collector accounts.
  2. SIMD-0185 which describes a new update to the vote program to set commission rates and collector accounts for 3 different revenue sources: inflation rewards, block fees (both base and priority), and block tips

I will also be drafting up a SIMD to design the syscall and/or system instruction for tipping the current leader

Comment on lines 74 to 81
If the commission rate and collector account for a revenue source aren't set,
all revenue will be collected into the validator's identity account as before.
If the commission rate and collector account for a revenue source *are*
specified, the commission amount MUST be calculated by first multiplying the
rate by the amount of revenue and then using integer division to divide by one
hundred. Then the commission amount should be deposited into the specified
collector address ONLY if the collector account is system program owned and
would be rent-exempt after the deposit.
Copy link
Contributor Author

@jstarry jstarry Oct 17, 2024

Choose a reason for hiding this comment

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

@michaelh-laine you previously wrote

When rewards distribution occurs the commission is applied to the collector account funds (commission paid to vote account) and balance included with rewards paid into stake accounts

But I think it would be better for validators if they could receive block fee revenue immediately after each block in order to have a stream of income to pay for voting costs rather than needing to wait for epoch boundaries. With this approach, an important thing to consider is how to design commission rate updates because it would be a little strange to allow commission to change multiple times throughout the epoch. Maybe the vote program should only support setting the commission for the upcoming epoch so that the current epoch commission rates are always fixed from the beginning of an epoch.

Choose a reason for hiding this comment

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

At most a validator would need to frontload 2 SOL to pay an epoch's voting fees, but I don't feel strongly about that component. Commission change should not be permitted after 50% of the epoch has elapsed the same as it is for staking and should apply for an entire epoch, agreed there.

Your proposal states commission should be paid to a system program-owned account, but I think a major use case here would be for larger and institutional validators to automatically divert those funds into a multisig for security and opsec purposes - this then naturally isn't a system-program owned account.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Commission change should not be permitted after 50% of the epoch has elapsed the same as it is for staking and should apply for an entire epoch, agreed there.

Hoping to make commission related updates only apply for the following epoch FYI. Will be updating #185 to reflect that design.

Your proposal states commission should be paid to a system program-owned account, but I think a major use case here would be for larger and institutional validators to automatically divert those funds into a multisig for security and opsec purposes - this then naturally isn't a system-program owned account.

Note that since you can define a system-program owned account that isn't your node validator id, it doesn't need to have a private key anymore and so you could use a PDA which is controlled by a multisig or other onchain program.

@jstarry jstarry marked this pull request as ready for review October 17, 2024 20:01
Copy link
Contributor

@tigarcia tigarcia left a comment

Choose a reason for hiding this comment

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

Adding some minor comments

After all transactions are processed in a block for a given leader, rather than
collecting all block revenue into the validator identity account, the protocol
will check if the validator's vote account has specified commission rates and
collector addresses in the new vote account version described in SIMD-XXXX.
Copy link
Contributor

Choose a reason for hiding this comment

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

Which SIMD is this referencing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should have been SIMD-0185

@jstarry
Copy link
Contributor Author

jstarry commented Feb 17, 2025

Addressed feedback and made a few design changes:

  1. Vote state must be fetched from the beginning of the epoch when determining the validator's fee collector account and commission. This means that these fields can be changed at any time but those changes will only be effective for the following epoch.
  2. Runtime will not create delegator rewards pool accounts if they don't exist yet. They must be created already and I'm thinking that this will be enforced by the vote program when setting a commission less than 100%.
  3. Commission is assumed to be specified in basis points rather than an integer percentage and therefore commission is calculated by rate / 10,000 instead of rate / 100.

@dimandotsol
Copy link

dimandotsol commented Feb 25, 2025

@jstarry due to the latest changes made here, I have a question (it is duplicated in 185, but I think it is more relevant here).

Will it be possible to add additional arbitrary lamports for the distribution?

@bartenbach
Copy link

Currently we have a rather unique model where I manually calculate and give away 5% of our block rewards to animal welfare organizations each month. I think this SIMD could help.

If they could be accrued in an arbitrary collection account and then (through DAO vote) transferred directly to a donation recipient's public donation address - that would be huge. Right now we have a bit of a "trust me bro" system. We've been audited in the past, but it's nonetheless not a great system for transparency.

It would be fantastic if we could build a front-end that could show our acquired block rewards in a provable way, and show those transfers to animal welfare organizations on a front end.

Right now, I'm tracking this with an Excel spreadsheet using formulas like it's 1995. My dream for a while has been to completely automate this process as much as possible. If this data was stored on chain, I could probably totally eliminate the spreadsheet.

@jstarry
Copy link
Contributor Author

jstarry commented Feb 25, 2025

Will it be possible to add additional arbitrary lamports for the distribution?

Yeah, planning to add a vote program instruction for that

@jstarry
Copy link
Contributor Author

jstarry commented Feb 27, 2025

If they could be accrued in an arbitrary collection account [..]

@bartenbach yes, that's the purpose of the block_rewards_collector field described in SIMD-0185. In your case, you could set your commission to 100% and have all funds to go to your custom block_rewards_collector account whose owner program is set to a custom program which has logic to divert 5% of rewards to the donation address. The remaining fees could be sent to your vote fee payer address or sent to the stakers who delegate stake to your node.

Below is an excerpt from this SIMD which loosely describes this mechanism:

After all transactions are processed in a block for a given leader, rather than
collecting all block revenue into the validator identity account, the protocol
will check if the validator's vote account has specified a commission rate and
collector addresses in the new vote account version described in SIMD-0185.
[..]
If the commission rate and collector account are specified, the calculated commission MUST be
deposited in the collector account and the remaining rewards MUST be deposited
into the validator's vote account for later distribution to stakers.

@autocatalytic
Copy link

Fair, and logical. And smart to keep this onchain for many reasons above.

Comment on lines 108 to 111
The delegator rewards amount MUST be calculated by subtracting the calculated
commission from the block fee revenue. If the delegator rewards amount is
non-zero, it must be added to the vote state field `pending_delegator_rewards`
and added to the balance of vote account.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This won't work currently because the vote account could have been closed by the time the validator produces their blocks. Vote accounts are close-able as long as they haven't earned any vote credits in both the current epoch or previous epoch. We might need to amend the vote program to prevent closing vote accounts that are part of the leader schedule.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think the best way to handle this edge case is to burn any delegator rewards that can't be recorded in an active vote account. Delegators that observe that their delegated vote account hasn't been voting for an epoch have time to redelegate and should do so because they will be missing out on inflation rewards anyways.

Copy link
Contributor

Choose a reason for hiding this comment

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

We might need to amend the vote program to prevent closing vote accounts that are part of the leader schedule.

i think there are other ways we can investigate to synchronize vote account liveness with the leader schedule

I think the best way to handle this edge case is to burn any delegator rewards that can't be recorded in an active vote account. Delegators that observe that their delegated vote account hasn't been voting for an epoch have time to redelegate and should do so because they will be missing out on inflation rewards anyways.

burn seems fine for now. inattentive stake is nothing to be rewarded

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 9ae2000

@jstarry
Copy link
Contributor Author

jstarry commented May 24, 2025

Here's the dependency graph of simd's:

graph TD
    %% Layer 1 - Base dependencies
    simd_0180["simd-0180<br/>vote keyed leader schedule"]
    simd_0185["simd-0185<br/>vote account v4"]
    simd_0249["simd-0249<br/>delay commission updates"]

    %% Layer 2 - Mid-tier proposals
    simd_0232["simd-0232<br/>custom commission addresses"]
    simd_0291["simd-0291<br/>commission rate in basis points"]
    simd_0232 --> simd_0180
    simd_0232 --> simd_0185
    simd_0291 --> simd_0185
    simd_0291 --> simd_0249

    %% Layer 3 - Top-level proposal
    simd_0123["simd-0123<br/>block revenue sharing"]
    simd_0123 --> simd_0180
    simd_0123 --> simd_0185
    simd_0123 --> simd_0232
    simd_0123 --> simd_0291
Loading

Comment on lines +142 to +148
When calculating stake delegation rewards for a particular completed reward
epoch, construct a list of all vote accounts that were initialized at the
beginning of the reward epoch and had a non-zero active stake delegation. For
each vote account, retrieve its state at the end of the reward epoch and check
the `pending_delegator_rewards` field in its vote state. Let this value be `P`.
If `P` is non-zero, use it to calculate rewards for each of the stake accounts
delegated to the vote account as follows:

Choose a reason for hiding this comment

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

It’s not very clear here, especially if you’re not a native speaker, I suspect. The version that refers to the previous epoch, the current epoch, and the first block of the current epoch is more unambiguous. Variants: the epoch for which rewards are earned - rewarded epoch, the epoch in which rewards are distributed - distribution epoch. Or you can use N and N-1 terminology for clarity. I generally prefer the approach used in SIMD-0118. It clearly defines what and when is taken from the state, what load from the snapshot (and save to), and how it all fits together.

Comment on lines +162 to +165
If no blocks in the epoch following the completed reward epoch have been
processed yet, subtract `B` from both the vote account’s lamport balance and its
`pending_delegator_rewards` field and store the updated vote account. Finally,
the burn amount `B` should also be deducted from the cluster capitalization.

Choose a reason for hiding this comment

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

I don’t think this is correct, or I didn’t understand the logic here.
Look,
7 * [0.1, 0.9] = [0.7, 6.3] -> [0, 6] -> 6
6 * [0.1, 0.9] = [0.6, 5.4] -> [0, 5] -> 5

Secondly, when we calculate rewards for stake accounts, we simply increase capitalization at the same moment. That is, if for some reason, by the time of calculation, the stake account or vote account no longer exists, it just won’t increase the capitalization (which reduces real inflation). However, in the case of the vote account, this will lead to unfair distribution (some stake accounts of the removed vote account may still manage to receive their rewards).

In the case of additional rewards, we move amounts from the vote account to the stake accounts. By the way, this will lead to writing all vote accounts every block (assuming the partition reward distribution is uniformly distributed), right?

I think it’s better to follow the approach of SIMD-0118, but we’ll have to use a sysvar for that (since capitalization is not increased). That is, in the first block of the epoch, record the reward distribution amounts by vote accounts into the sysvar data, and move that amount to the sysvar. This way, we can avoid the error of double discarding the fractional part (which I described above), reduce the number of accounts written to in each block, and overall allows us to lift the restriction on deleting a vote account before distribution is complete (I think this was mentioned in the description of the v4 vote program).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. There isn't any double discarding. We only discard leftover lamports when portioning out the pending rewards to each stake account.
  2. Yes, in addition to writing all the stake accounts for a partition, we will also modify all of the vote accounts that were delegated to by those stake accounts. We could just write all vote accounts once at the boundary and move the pending rewards into a sysvar as you suggested. I like that better actually, I'll write up an amendment proposal.

Choose a reason for hiding this comment

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

Perhaps I wasn’t entirely precise. The two-line example above is actually a single example. If there were only one field pending_delegator_rewards, it wouldn’t be sufficient. The example assumes a total of 7 lamports to be distributed and two stakers with shares of 0.1 and 0.9 for the validator. If calculated at the beginning of the epoch, the stakers would receive 0 and 6 lamports, respectively. And we would immediately decrease pending_delegator_rewards by 1 lamport. But then, during actual distribution, we would get 0 and 5 lamports due to truncation. And 1 lamport would remain undistributed.

To avoid this, we need to store the original value of pending_delegator_rewards.

Thus, we need two fields - one to store new rewards for the current epoch and another to store the original value from the previous epoch. The remaining amount to be distributed is not strictly necessary.

In any case, using a sysvar moves these problems out of the vote account state. The sysvar data can store only the original unmodified amount, and the balance transfer from the vote account can be done using the reduced value.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We use the original value of pending rewards from the epoch boundary for each of the stake account calculations

Choose a reason for hiding this comment

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

Yes, yes, I understand. But the entire paragraph refers to “If no blocks in the epoch…” and then “…and store the updated vote account”. So it looks like the actual value will already be lost by the second block of the epoch. But the actual funding of stake accounts will happen later. And at that point, the original value will be needed again (because without it, the error I described in the example will occur). And yes, I’m assuming here that this value is stored somewhere in the state, not just in the Banks at validator runtime.

But I saw the new thread. I think it makes sense to move the discussion there.

@Benhawkins18 Benhawkins18 self-requested a review June 9, 2025 19:51
Copy link
Collaborator

@Benhawkins18 Benhawkins18 left a comment

Choose a reason for hiding this comment

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

Got approvals from all teams, governance passed. Merging

@Benhawkins18 Benhawkins18 merged commit 9926e97 into solana-foundation:main Jun 9, 2025
2 checks passed
@jstarry jstarry deleted the block-fee-distribution branch June 9, 2025 20:35
@jstarry jstarry mentioned this pull request Jun 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.