-
Notifications
You must be signed in to change notification settings - Fork 179
SIMD-0185: Vote Account v4 #185
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
Changes from 8 commits
9d8dedb
ddc80c2
68a231b
2651ce6
08d0088
b66ad3a
a106539
0b2c2bd
de1e88f
09d8017
3b9bad3
b68e95e
07edc01
34d0b02
cb99089
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,244 @@ | ||
--- | ||
simd: '0185' | ||
title: Vote Account v4 | ||
authors: Justin Starry (Anza) | ||
category: Standard | ||
type: Core | ||
status: Review | ||
created: 2024-10-17 | ||
feature: (fill in with feature tracking issues once accepted) | ||
--- | ||
|
||
## Summary | ||
|
||
Add a new version of vote account state which clears unused state to make | ||
room for new state information. | ||
|
||
## Motivation | ||
|
||
A new update for the vote program is proposed to improve authorized voter | ||
bookkeeping as well as initialize state fields that will allow validators to set | ||
commission rates and collector accounts for different revenue sources in the | ||
future. | ||
|
||
### Authorized voter bookkeeping | ||
|
||
- Over 40% of vote state size is reserved for tracking a history of 32 prior | ||
authorized voters for the vote account in the `prior_voters` field. Having such | ||
a long history of prior voters is arguably not very useful, tracking the most | ||
recent previous epoch's voter is probably sufficient and can be stored in the | ||
`authorized_voters` field instead. | ||
|
||
- The `authorized_voters` field doesn't store the voter for the previous epoch | ||
so it's impossible to have a transition epoch where both the previous and newly | ||
assigned voter can both sign votes. | ||
|
||
### Revenue Collection Customization | ||
|
||
- There is only one commission rate stored in vote account state but validators | ||
want to be able to use different commission rates for different income streams | ||
like block revenue. | ||
|
||
- It's not possible to customize which accounts income is collected into. | ||
Currently all block fee revenue is collected into the validator identity account | ||
which cannot be a cold wallet since the identity needs to sign a lot of messages | ||
for various network protocols used in Solana like turbine, gossip, and QUIC. | ||
|
||
## Alternatives Considered | ||
|
||
### Reuse vote commission | ||
|
||
Vote accounts already allow validators to set a commission rate for inflation | ||
rewards and so it's not unreasonable to expect that this commission rate could | ||
also be used to distribute block revenue. However, some validators have | ||
expressed a desire to be able to tune revenue streams independently. | ||
|
||
## New Terminology | ||
|
||
- Block Revenue Commission: The commission rate that determines how much of | ||
block base fee and priority fee revenue is collected by the validator before | ||
distributing remaining funds to stake delegators. Previously 100% of block | ||
revenue was distributed to the validator identity account. | ||
|
||
- Inflation Rewards Commission: The commission rate that determines how much of | ||
stake inflation rewards are collected by the validator before distributing the | ||
remaining rewards to stake delegators. Previously referred to as simply the | ||
"commission" since there was no need to differentiate from other types of | ||
commission. | ||
|
||
- Block Revenue Commission Collector: The account used to collect commissioned | ||
block revenue for validators. Previously collected by default into the validator | ||
identity account. | ||
|
||
- Inflation Rewards Commission Collector: The account used to collect | ||
commissioned inflation rewards for validators. Previously collected by default | ||
into the vote account. | ||
|
||
## Detailed Design | ||
|
||
Currently, all block revenue, including both transaction base fees and priority | ||
fees, is collected into a validator's node id account. This proposal details | ||
changes to the vote account state that will allow validators to specify how | ||
different sources of income are collected in future SIMD's. This proposal also | ||
updates the bookkeeping for authorized voters in the vote account state. | ||
|
||
### Vote Account | ||
|
||
A new version of vote state will be introduced with the enum discriminant value | ||
of `3u32` which will be little endian encoded in the first 4 bytes of account | ||
data. | ||
|
||
```rust | ||
pub enum VoteStateVersions { | ||
V1(..), | ||
V2(..), | ||
V3(..), | ||
V4(..), // <- new variant | ||
} | ||
``` | ||
|
||
This new version of vote state will include new fields for setting the | ||
commission and collector account for the following sources of validator income: | ||
inflation rewards and block revenue. It will also remove the `prior_voters` | ||
field. | ||
|
||
```rust | ||
pub struct VoteStateV4 { | ||
pub node_pubkey: Pubkey, | ||
pub authorized_withdrawer: Pubkey, | ||
|
||
/// REMOVED | ||
/// commission: u8, | ||
|
||
/// NEW: the collector accounts for validator income | ||
pub inflation_rewards_collector: Pubkey, | ||
pub block_revenue_collector: Pubkey, | ||
|
||
/// NEW: basis points (0-10,000) that represent how much of each income | ||
/// source should be given to this VoteAccount | ||
pub inflation_rewards_commission_bps: u16, | ||
pub block_revenue_commission_bps: u16, | ||
buffalojoec marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/// NEW: reward amount pending distribution to stake delegators | ||
pub pending_delegator_rewards: u64, | ||
|
||
pub votes: VecDeque<LandedVote>, | ||
pub root_slot: Option<Slot>, | ||
pub authorized_voters: AuthorizedVoters, | ||
buffalojoec marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/// REMOVED | ||
/// prior_voters: CircBuf<(Pubkey, Epoch, Epoch)>, | ||
|
||
pub epoch_credits: Vec<(Epoch, u64, u64)>, | ||
pub last_timestamp: BlockTimestamp, | ||
} | ||
``` | ||
|
||
### Vote Program | ||
|
||
All vote instructions MUST be updated to support deserializing v4 vote accounts. | ||
|
||
Whenever a vote account is initialized OR modified by the vote program in a | ||
transaction AND hasn't been updated to v4 yet, the account state MUST be saved | ||
in the new format with the following default values for the new fields described | ||
above: | ||
|
||
```rust | ||
VoteStateV4 { | ||
// .. | ||
|
||
inflation_rewards_collector: Pubkey::default(), | ||
block_rewards_collector: Pubkey::default(), | ||
inflation_rewards_commission_bps: 100u16 * (old_vote_state.commission as u16), | ||
block_rewards_commission_bps: 10_000u16, | ||
pending_delegator_rewards: 0u64, | ||
|
||
// .. | ||
} | ||
``` | ||
|
||
If a modified vote account's size is smaller than `3762` bytes, first resize the | ||
account to `3762` bytes before updating the account data. The vote program does | ||
not need to check if the resulting account is rent exempt, the runtime will | ||
enforce that check. This differs from the prior vote program implementation which | ||
buffalojoec marked this conversation as resolved.
Show resolved
Hide resolved
|
||
falls back to store vote state as v2 if the account size cannot be resized while | ||
keeping the account rent exempt. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I felt this was nice to have because it simplifies the vote program implementation and ensures that all v4 vote accounts have the same size. Here's the current code in question that this will clean up:
buffalojoec marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
### `InitializeAccount` | ||
|
||
The required size for vote accounts previously set to `3762` bytes MUST remain | ||
unchanged despite freeing up space with the removal of the prior voters field. | ||
Keeping the same size requirement simplifies this proposal and leaves extra | ||
space for future fields. | ||
|
||
Note that a v4 vote account is ALWAYS considered initialized, because unlike | ||
other vote state versions, it's never stored with uninitialized state. | ||
|
||
#### `UpdateCommission` | ||
|
||
The existing `UpdateCommission` instruction will will continue to only update | ||
the inflation rewards commission in integer percentage values. | ||
|
||
When updating vote state v4 accounts, the new `inflation_rewards_commission_bps` | ||
field should be used instead of the old generic `commission` field. | ||
Additionally, the new commission value MUST be multiplied by `100` before being | ||
checked for commission or increases and before being stored in account data. | ||
|
||
#### `Authorize`, `AuthorizeChecked`, `AuthorizeWithSeed`, `AuthorizeCheckedWithSeed` | ||
|
||
Existing authorize instructions will be processed differently when setting new | ||
authorized voters. Rather than purging authorized voter entries from the | ||
`authorized_voters` field that correspond to epochs less than the current epoch, | ||
only purge entries less than the previous epoch (current epoch - 1). This will | ||
mean that the `authorized_voters` field can now hold up to 4 entries for the | ||
epochs in the range `[current_epoch - 1, current_epoch + 2]`. Keeping the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is there a reason we need to store There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah that's the current design and I think it kinda makes sense because otherwise you could set a new authorized voter at the end of an epoch and immediately start using it in the next block in the new epoch and leaders would need an up to date view on any new authorized voters for each fork crossing the epoch boundary |
||
authorized voter around from the previous epoch will allow the protocol to | ||
accept votes from both the current and previous authorized voters to make voter | ||
transitions smoother. | ||
|
||
Additionally, since the `prior_voters` field is removed from vote state v4, | ||
there's no need to read or modify this field when processing authorize | ||
instructions. | ||
|
||
#### `Withdraw` | ||
|
||
The existing withdraw instruction MUST be modified to completely zero vote | ||
account data for fully withdrawn vote accounts. The old behavior partially | ||
zeroed the account data following the vote state version discriminant and is | ||
less intuitive. | ||
Comment on lines
+213
to
+216
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I felt this was a nice to have change. This way we know that any vote account with the version discriminant bytes There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems reasonable to me, unless there's some reason it's done like this currently? Seems strange to keep that discriminator set afterward. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No explicit reason that I'm aware of. We will need an extra look from auditors at this though. |
||
|
||
### Stake Program | ||
|
||
The builtin stake program reads vote account state when creating, delegating, | ||
and deactivating stake accounts. The program MUST be updated to support v4 vote | ||
accounts. | ||
|
||
### Other | ||
|
||
The runtime stakes cache and epoch stakes stored in snapshots MUST also be updated | ||
to support initialized v4 vote accounts. | ||
|
||
The tower serialization format MUST remain unchanged and continue serializing tower | ||
vote state as vote state v2. | ||
|
||
## Impact | ||
|
||
This is a prerequisite for implementing other SIMD's like block reward | ||
distribution in [SIMD-0123] which give validators more flexibility in how | ||
inflation rewards and block revenue is collected and distributed. | ||
|
||
[SIMD-0123]: https://github.com/solana-foundation/solana-improvement-documents/pull/123 | ||
|
||
## Security Considerations | ||
|
||
NA | ||
|
||
## Drawbacks *(Optional)* | ||
|
||
NA | ||
|
||
## Backwards Compatibility *(Optional)* | ||
|
||
Existing programs that read vote state will need to be updated to support the | ||
latest account state version. |
Uh oh!
There was an error while loading. Please reload this page.