-
Notifications
You must be signed in to change notification settings - Fork 94
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
SIMD-0185: Vote Account v4 #185
Draft
jstarry
wants to merge
2
commits into
solana-foundation:main
Choose a base branch
from
jstarry:vote-account-v4
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,231 @@ | ||
--- | ||
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 | ||
|
||
A new update for the vote program is proposed to improve authorized voter | ||
bookkeeping as well as allow validators to set commission rates and collector | ||
accounts for different revenue sources. | ||
|
||
## Motivation | ||
|
||
This SIMD details two different modifications to the vote program and vote | ||
account state and combines these changes into one proposal so that only | ||
one vote account version update is needed. | ||
|
||
### 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 rewards. | ||
|
||
- It's not possible to customize which accounts income is collected into. | ||
Currently all block rewards are 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. | ||
|
||
### 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. | ||
|
||
## 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 rewards. However, some validators have | ||
expressed a desire to be able to tune revenue streams indpendently. | ||
|
||
## New Terminology | ||
|
||
- Block Rewards Collector: The account used to collect commissioned block | ||
rewards for validators. Previously collected by default into the validator | ||
identity account. | ||
|
||
- Inflation Rewards Collector: The account used to collect commissioned | ||
inflation rewards for validators. Previously collected by default into the vote | ||
account. | ||
|
||
- Block Rewards 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 | ||
rewards were 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. | ||
|
||
## Detailed Design | ||
|
||
Currently, all block fees, including both transaction base fees and priority | ||
fees, are collected into a validator's node id account. This proposal details | ||
changes to the Vote Program and Vote Account that will allow validators to | ||
specify how different sources of income are collected. 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 each of the sources of validator income: | ||
inflation rewards and block rewards. It will also remove the `prior_voters` | ||
field. | ||
|
||
```rust | ||
pub struct VoteStateV4 { | ||
pub node_pubkey: Pubkey, | ||
pub authorized_withdrawer: Pubkey, | ||
|
||
/// NEW: the collector accounts for validator income | ||
pub inflation_rewards_collector: Pubkey, | ||
pub block_rewards_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_rewards_commission_bps: u16, | ||
|
||
/// NEW: bump seed for deriving this vote account's stake rewards pool address | ||
pub stake_rewards_pool_bump_seed: u8, | ||
|
||
/// REMOVED | ||
/// prior_voters: CircBuf<(Pubkey, Epoch, Epoch)>, | ||
|
||
pub votes: VecDeque<LandedVote>, | ||
pub root_slot: Option<Slot>, | ||
pub authorized_voters: AuthorizedVoters, | ||
pub epoch_credits: Vec<(Epoch, u64, u64)>, | ||
pub last_timestamp: BlockTimestamp, | ||
} | ||
``` | ||
|
||
Whenever a vote account is 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: vote_state_v3.node_pubkey, | ||
block_rewards_collector: vote_state_v3.node_pubkey, | ||
inflation_rewards_commission_bps: 100u16 * (vote_state_v3.commission as u16), | ||
block_rewards_commission_bps: 10_000u16, | ||
stake_rewards_pool_bump_seed: find_stake_rewards_pool_bump_seed(vote_pubkey), | ||
|
||
// .. | ||
} | ||
|
||
fn find_stake_rewards_pool_bump_seed(vote_pubkey: &Pubkey) -> u8 { | ||
Pubkey::find_program_address( | ||
[ | ||
b"stake_rewards_pool", | ||
vote_pubkey.as_ref(), | ||
], | ||
&stake_program::id(), | ||
).1 | ||
} | ||
``` | ||
|
||
### Vote Program | ||
|
||
```rust | ||
pub enum VoteInstruction { | ||
// .. | ||
UpdateCommission {..} // 5u32 | ||
// .. | ||
UpdateCommissionWithKind { // 16u32 | ||
commission_bps: u16, | ||
kind: CollectorKind, | ||
}, | ||
UpdateCollectorAccount { // 17u32 | ||
pubkey: Pubkey, | ||
kind: CollectorKind, | ||
}, | ||
} | ||
|
||
#[repr(u8)] | ||
pub enum CollectorKind { | ||
InflationRewards = 0, | ||
BlockRewards, | ||
} | ||
``` | ||
|
||
#### `UpdateCommission` | ||
|
||
The existing `UpdateCommission` instruction (with enum discriminant `5u32`) will | ||
continue to exist but will continue to only update the inflation rewards | ||
commission. | ||
|
||
#### `UpdateCommissionWithKind` | ||
|
||
A new instruction for setting different kinds of commissions will be added to | ||
the vote program with the enum discriminant of `16u32` little endian encoded in | ||
the first 4 bytes. | ||
|
||
#### `UpdateCollectorAccount` | ||
|
||
A new instruction for setting collector accounts will be added to the vote | ||
program with the enum discriminant value of `17u32` little endian encoded in the | ||
first 4 bytes. | ||
|
||
#### `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 | ||
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. | ||
|
||
## Impact | ||
|
||
This is a prerequisite for implementing block reward distribution in SIMD-0123. | ||
|
||
## Security Considerations | ||
|
||
What security implications/considerations come with implementing this feature? | ||
Are there any implementation-specific guidance or pitfalls? | ||
|
||
## Drawbacks *(Optional)* | ||
|
||
Why should we not do this? | ||
|
||
## Backwards Compatibility *(Optional)* | ||
|
||
Does the feature introduce any breaking changes? All incompatibilities and | ||
consequences should be listed. |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a reason we need to store
current_epoch + 2
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The 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