Skip to content

Commit 9926e97

Browse files
authored
SIMD-0123: Block Revenue Distribution (#123)
* SIMD-0123: Block Fee Distribution * update simd and update title to block revenue * update status to make linter happy * remove tips, explain 9% activation limit, and detail calculations * feedback and revisions * fix lint issues * clarify vote state fetching * Store pending rewards in vote account * fix lint * closed vote account edge case * don't limit to leader schedule vote accounts * update based on simd breakup * clarify dependencies * update simd-0249 ref * update simd-0249 to simd-0291
1 parent 287550e commit 9926e97

File tree

1 file changed

+250
-0
lines changed

1 file changed

+250
-0
lines changed
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
---
2+
simd: '0123'
3+
title: Block Revenue Sharing
4+
authors: Justin Starry (Anza)
5+
category: Standard
6+
type: Core
7+
status: Review
8+
created: 2024-03-10
9+
feature: (fill in with feature tracking issues once accepted)
10+
---
11+
12+
## Summary
13+
14+
A new mechanism is proposed to allow validators to share part of their block
15+
revenue with their delegators. Commission rates from validator vote accounts
16+
will be used by the protocol to calculate post-commission rewards that will be
17+
automatically distributed to delegated stake accounts after an epoch is
18+
completed.
19+
20+
## Motivation
21+
22+
Delegated stake directly increases the number of blocks that a validator is
23+
allocated in an epoch leader schedule but the core protocol doesn't support
24+
diverting any of that extra revenue to stake delegators.
25+
26+
## Dependencies
27+
28+
This proposal depends on the following previously accepted proposals:
29+
30+
- **[SIMD-0180]: Use Vote Account Address To Key Leader Schedule**
31+
32+
Necessary for looking up a block producer's vote account
33+
34+
- **[SIMD-0185]: Vote Account v4**
35+
36+
Introduces version 4 of the vote account state, which adds new fields
37+
for block revenue commission and pending delegation rewards
38+
39+
- **[SIMD-0232]: Custom Commission Collector Account**
40+
41+
Necessary for looking up a block producer's commission collector account
42+
43+
- **[SIMD-0291]: Commssion Rate in Basis Points**
44+
45+
Introduces a new instruction type for setting commission rates in basis
46+
points
47+
48+
[SIMD-0180]: https://github.com/solana-foundation/solana-improvement-documents/pull/180
49+
[SIMD-0185]: https://github.com/solana-foundation/solana-improvement-documents/pull/185
50+
[SIMD-0232]: https://github.com/solana-foundation/solana-improvement-documents/pull/232
51+
[SIMD-0291]: https://github.com/solana-foundation/solana-improvement-documents/pull/291
52+
53+
## Alternatives Considered
54+
55+
### Distribute Rewards as Activated Stake
56+
57+
The runtime could ensure that any distributed stake rewards get activated as
58+
well but it would require extra complexity in the protocol to support that
59+
feature. Instead, stakers will receive inactive SOL in their stake accounts that
60+
they will have to manage themselves. [SIMD-0022] aims to make this experience
61+
better for stakers by allowing stake accounts to separately delegate any
62+
unstaked balance in their accounts.
63+
64+
[SIMD-0022]: https://github.com/solana-foundation/solana-improvement-documents/pull/22
65+
66+
### Out of protocol reward distribution
67+
68+
Due to the lack of core protocol support for distributing block revenue to
69+
stakers, validators have developed their own solutions which are not enforced by
70+
the core protocol. For example, the Cogent validator diverts part of its fee
71+
revenue to NFT holders. But it's up the NFT holders to audit and hold Cogent
72+
accountable to a specific commission rate.
73+
74+
Another alternative is Jito's mechanism for block "tips" (not fees, but the idea
75+
is similar). Jito's validator implementation includes a tip distribution program
76+
which it instructs validator operators to divert all of their tips to but cannot
77+
enforce perfect compliance. It's up to stakers and the Jito team to audit
78+
compliance by validator operators. This mechanism requires trusting a
79+
third-party (in this case Jito) to calculate reward distribution in an accurate
80+
and fair manner. It also relies on using a merkle tree to distribute fees to all
81+
stake accounts and the distributed fees are not automatically staked in
82+
recipient stake accounts.
83+
84+
## New Terminology
85+
86+
NA
87+
88+
## Detailed Design
89+
90+
### Runtime: Block Revenue Collection
91+
92+
After all transactions are processed in a block for a given leader, rather than
93+
collecting all block revenue into the validator identity account, the protocol
94+
will look up the block producer's vote account as described in [SIMD-0180]. Then
95+
it MUST check if the validator's vote account has specified a block revenue
96+
commission rate and collector addresses in the new vote account version
97+
described in [SIMD-0185]. As described in [SIMD-0232], the latest block revenue
98+
commission rate and collector address MUST be loaded from the vote account state
99+
at the beginning of the previous epoch. This is the same vote account state used
100+
to build the leader schedule for the current epoch.
101+
102+
If the block revenue commission rate and collector account aren't set (e.g., the
103+
vote account state version has not been updated to v4 yet), all revenue will be
104+
collected into the validator's identity account as before. If the block revenue
105+
commission rate and collector account *are* specified, the rewards MUST be
106+
distributed according to the commission and delegator rewards collection
107+
sections below.
108+
109+
#### Commission Collection
110+
111+
The commission amount MUST be calculated by first multiplying the amount of
112+
revenue by the lesser of the vote account's block revenue commission rate or the
113+
maximum of `10,000` basis points. Then use integer division to divide by
114+
`10,000` and discard the remainder. If the commission amount is non-zero, the
115+
block revenue commission collector account MUST be loaded and checked for the
116+
following conditions:
117+
118+
1. account is system program owned AND
119+
2. account is rent-exempt after depositing the commission.
120+
121+
If the conditions are met, the commission amount MUST be deposited into the
122+
block revenue commission collector account. If either of these conditions is
123+
violated, the commission amount MUST be burned.
124+
125+
#### Delegator Rewards Collection
126+
127+
The delegator rewards amount MUST be calculated by subtracting the calculated
128+
commission from the block fee revenue. If the delegator rewards amount is
129+
non-zero, the vote account must be loaded and checked for the following
130+
conditions:
131+
132+
1. account is vote program owned AND
133+
2. account is initialized with vote state v4 or later
134+
135+
If the conditions are met, the delegator rewards amount MUST be added to the
136+
vote state field `pending_delegator_rewards` and added to the balance of vote
137+
account. If either of these conditions is violated, the delegator rewards amount
138+
MUST be burned.
139+
140+
### Runtime: Delegator Rewards Distribution
141+
142+
When calculating stake delegation rewards for a particular completed reward
143+
epoch, construct a list of all vote accounts that were initialized at the
144+
beginning of the reward epoch and had a non-zero active stake delegation. For
145+
each vote account, retrieve its state at the end of the reward epoch and check
146+
the `pending_delegator_rewards` field in its vote state. Let this value be `P`.
147+
If `P` is non-zero, use it to calculate rewards for each of the stake accounts
148+
delegated to the vote account as follows:
149+
150+
1. Sum all active stake delegated to the vote account during the reward epoch
151+
epoch. Let this total be `A`.
152+
153+
2. For each individual stake account, multiply its active stake from the
154+
reward epoch by `P`, and divide the result by `A` using integer division.
155+
Discard any fractional lamports.
156+
157+
After calculating all individual stake rewards, sum them to obtain `D`, the
158+
total distribution amount. Because of integer division, the full amount `P` may
159+
not be distributed so compute the amount to be burned, `B`, as the difference
160+
between `P` and `D`.
161+
162+
If no blocks in the epoch following the completed reward epoch have been
163+
processed yet, subtract `B` from both the vote account’s lamport balance and its
164+
`pending_delegator_rewards` field and store the updated vote account. Finally,
165+
the burn amount `B` should also be deducted from the cluster capitalization.
166+
167+
#### Individual Delegator Reward
168+
169+
The stake reward distribution amounts for each stake account calculated above
170+
can then be used to construct a list of stake reward entries which MUST be
171+
partitioned and distributed according to [SIMD-0118].
172+
173+
When reward entries are used to distribute rewards pool funds during partitioned
174+
rewards distribution, the delegated vote account for each rewarded stake account
175+
must have its `pending_delegator_rewards` field and its balance deducted with
176+
the amount of rewards distributed to keep capitalization consistent.
177+
178+
[SIMD-0118]: https://github.com/solana-foundation/solana-improvement-documents/pull/118
179+
180+
### Vote Program
181+
182+
#### Withdraw
183+
184+
Since pending delegator rewards will be stored in the validator's vote account
185+
until distribution at the next epoch boundary, those funds will be unable to be
186+
withdrawn.
187+
188+
The `Withdraw` instruction must be modified so that if the balance indicated by
189+
the `pending_delegator_rewards` field is non-zero, the vote account will no
190+
longer be closeable by fully withdrawing funds. The withdrawable balance when
191+
`pending_delegator_rewards` is non-zero will be equal to the vote account's
192+
balance minus `pending_delegator_rewards` and the minimum rent exempt balance.
193+
194+
#### UpdateCommissionBps
195+
196+
The `UpdateCommissionBps` instruction added in [SIMD-0291] must be updated to
197+
add support for updating the block revenue commission rate.
198+
199+
When the specified commission kind is `CommissionKind::BlockRevenue`, update the
200+
`block_revenue_commission_bps` field instead of the previous behavior of
201+
returning an `InstructionError::InvalidInstructionData`.
202+
203+
Note that the commission rate is allowed to be set and stored as any `u16` value
204+
but as detailed above, it will capped at 10,000 during the actual commission
205+
calculation.
206+
207+
#### DepositDelegatorRewards
208+
209+
A new instruction for distributing lamports to stake delegators will be added to
210+
the vote program with the enum discriminant value of `18u32` little endian
211+
encoded in the first 4 bytes.
212+
213+
```rust
214+
pub enum VoteInstruction {
215+
/// # Account references
216+
/// 0. `[WRITE]` Vote account to be updated with the deposit
217+
/// 1. `[SIGNER, WRITE]` Source account for deposit funds
218+
DepositDelegatorRewards { // 18u32
219+
deposit: u64,
220+
},
221+
}
222+
```
223+
224+
Perform the following checks:
225+
226+
- If the number of account inputs is less than 2, return
227+
`InstructionError::NotEnoughAccountKeys`
228+
- If the vote account (index `0`) fails to deserialize, return
229+
`InstructionError::InvalidAccountData`
230+
- If the vote account is not initialized with state version 4, return
231+
`InstructionError::InvalidAccountData`
232+
233+
Then the processor should perform a system transfer CPI of `deposit` lamports
234+
from the source account (index `1`) to the vote account. Lastly, increment the
235+
`pending_delegator_rewards` value by `deposit`.
236+
237+
## Impact
238+
239+
Stake delegators will receive additional income when delegating to validators
240+
who adopt this new feature by setting a block revenue commission rate less than
241+
the default of `100%`.
242+
243+
## Security Considerations
244+
245+
NA
246+
247+
## Backwards Compatibility
248+
249+
A feature gate will be used to enable block reward distribution at an epoch
250+
boundary.

0 commit comments

Comments
 (0)