Open
Conversation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add VoteState4 struct with all V4 fields (inflation/block revenue collectors, commission as u16 bps, pending delegator rewards, BLS pubkey). Handle discriminant 3 in all VoteStateVersions switch sites (unmarshal, marshal, IsInitialized, ConvertToCurrent, LastTimestamp, NodePubkey). V4 write path serializes as discriminant 3 with no V1_14_11 fallback on resize failure (returns AccountNotRentExempt per SIMD-0185). Preserve V4-specific fields through the VoteState working struct round-trip; first-time V3→V4 conversion defaults match Agave (inflation_rewards_collector=vote_pubkey, block_revenue_collector= node_pubkey). Behavioral changes: V4 purges authorized voters at currentEpoch-1 (retains one extra epoch) and skips PriorVoters tracking. Update all external consumers (rewards, transaction, manifest_decoder). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Implements SIMD-0185 (Vote State V4), the next structural revision of the on-chain vote account format. V4 removes
PriorVoters, changes commission fromu8percentage tou16basis points, and adds new fields for revenue splitting and BLS keys. Gated behind featurevote_state_v4(Gx4XFcrVMt4HUvPzTpTSVkdDVgcDSjKhDN1RqRS6KDuZ).Changes
New struct and serialization (
pkg/sealevel/vote_state.go)VoteState4struct with all V4 fields:InflationRewardsCollector,BlockRevenueCollector,InflationRewardsCommissionBps(u16),BlockRevenueCommissionBps(u16),PendingDelegatorRewards,BlsPubkeyCompressed(Option<[u8;48]>), plus the standard fields (NodePubkey, AuthorizedWithdrawer, Votes as LandedVote deque, RootSlot, AuthorizedVoters, EpochCredits, LastTimestamp).VoteStateVersionV4) added to the existing iota enum (V0_23_5=0, V1_14_11=1, Current/V3=2, V4=3).UnmarshalWithDecoderandMarshalWithEncodermatching Agave's frame_v4 layout byte-for-byte.VoteStateVersions switch sites
All 6 switch sites in
VoteStateVersionsupdated with V4 cases:UnmarshalWithDecoder/MarshalWithEncoder— delegates to VoteState4 codecIsInitialized— checks V4 AuthorizedVoters lengthConvertToCurrent— converts V4 to the VoteState working struct, preserving V4-specific fields via internal preservation fields (wasV4,v4InflationRewardsCollector, etc.)LastTimestamp/NodePubkey— direct field access on V4V4 field preservation through the processing loop
Mithril processes all vote state versions through a common
VoteState(V3) working struct. V4-only fields (collectors, bps commission, pending rewards, BLS key) are preserved via unexported fields onVoteState. On write-back:wasV4 = true: preserved original V4 values are restored (no lossy round-trip)wasV4 = false(first V3→V4 conversion): Agave-matching defaults are used:InflationRewardsCollector= vote account pubkeyBlockRevenueCollector= node pubkeyInflationRewardsCommissionBps=u8_commission * 100BlockRevenueCommissionBps= 10000 (100%)PendingDelegatorRewards= 0,BlsPubkeyCompressed= NoneWrite path (
setVoteAccountState)When
VoteStateV4feature is active (checked BEFOREVoteStateAddVoteLatency):newVoteState4FromCurrentInstrErrAccountNotRentExemptper SIMD-0185VoteProgramUpdateCommissionsync the preservedv4InflationRewardsCommBpsfieldBehavioral changes
currentEpoch - 1(retains one extra epoch), vs V3'scurrentEpoch. Implemented inGetAndUpdateAuthorizedVoterwhich now acceptsfeatures.Features.SetNewAuthorizedVoterskipsPriorVoters.Appendwhen V4 is active (V4 has no PriorVoters field). Both methods now acceptfeatures.Features.External consumer updates
pkg/sealevel/vote_program.go:verifyAndGetVoteStatesignature updated to accept features; all 3 callers (VoteProgramProcessVote,VoteProgramProcessVoteStateUpdate,VoteProgramProcessTowerSync) pass features through.VoteProgramAuthorizepasses features toSetNewAuthorizedVoter.pkg/rewards/rewards.go:voteCommissionSplitreads V4InflationRewardsCommissionBps / 100;calculateStakePointsAndCreditsreads V4EpochCredits.pkg/replay/transaction.go:recordVoteTimestampAndSlotreads V4LastTimestamp.pkg/snapshot/manifest_decoder.go: Snapshot vote account loading handles V4LastTimestampandNodePubkey.Correctness notes
agave/programs/vote/src/vote_state/handler.rs(convert_to_v4, V4 purge, V4 set_new_authorized_voter skips prior_voters)🤖 Generated with Claude Code