From c58a057e3715f3079646c6ca7bc043180a237cd3 Mon Sep 17 00:00:00 2001 From: Wen <113942165+wen-coding@users.noreply.github.com> Date: Mon, 3 Nov 2025 18:50:53 -0800 Subject: [PATCH 1/9] Add VoteInitV2 and new variant in VoteAuthorize to add BLS Pubkey to vote program. --- Cargo.lock | 1 + vote-interface/Cargo.toml | 2 + vote-interface/src/instruction.rs | 59 ++++++++++++++++++- vote-interface/src/state/mod.rs | 3 + .../src/state/vote_instruction_data.rs | 50 +++++++++++++++- vote-interface/src/state/vote_state_v4.rs | 16 ++++- 6 files changed, 127 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ef0926186..70851410c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3989,6 +3989,7 @@ dependencies = [ "num-traits", "rand", "serde", + "serde_bytes", "serde_derive", "serde_with", "solana-clock", diff --git a/vote-interface/Cargo.toml b/vote-interface/Cargo.toml index f127b968d..36175014a 100644 --- a/vote-interface/Cargo.toml +++ b/vote-interface/Cargo.toml @@ -38,6 +38,7 @@ frozen-abi = [ serde = [ "dep:cfg_eval", "dep:serde", + "dep:serde_bytes", "dep:serde_derive", "dep:serde_with", "dep:solana-serde-varint", @@ -54,6 +55,7 @@ cfg_eval = { workspace = true, optional = true } num-derive = { workspace = true } num-traits = { workspace = true } serde = { workspace = true, optional = true } +serde_bytes = { workspace = true, optional = true } serde_derive = { workspace = true, optional = true } serde_with = { workspace = true, features = ["macros"], optional = true } solana-clock = { workspace = true } diff --git a/vote-interface/src/instruction.rs b/vote-interface/src/instruction.rs index 599755eea..e4a0ec409 100644 --- a/vote-interface/src/instruction.rs +++ b/vote-interface/src/instruction.rs @@ -4,7 +4,7 @@ use { super::state::TowerSync, crate::state::{ Vote, VoteAuthorize, VoteAuthorizeCheckedWithSeedArgs, VoteAuthorizeWithSeedArgs, VoteInit, - VoteStateUpdate, VoteStateV4, + VoteInitV2, VoteStateUpdate, VoteStateV4, }, solana_clock::{Slot, UnixTimestamp}, solana_hash::Hash, @@ -34,6 +34,15 @@ pub enum VoteInstruction { /// 3. `[SIGNER]` New validator identity (node_pubkey) InitializeAccount(VoteInit), + // Initialize a vote account using VoteInitV2 + /// + /// # Account references + /// 0. `[WRITE]` Uninitialized vote account + /// 1. `[]` Rent sysvar + /// 2. `[]` Clock sysvar + /// 3. `[SIGNER]` New validator identity (node_pubkey) + InitializeAccountV2(VoteInitV2), + /// Authorize a key to send votes or issue a withdrawal /// /// # Account references @@ -265,6 +274,23 @@ fn initialize_account(vote_pubkey: &Pubkey, vote_init: &VoteInit) -> Instruction ) } +#[cfg(feature = "bincode")] +fn initialize_account_v2(vote_pubkey: &Pubkey, vote_init: &VoteInitV2) -> Instruction { + let account_metas = vec![ + AccountMeta::new(*vote_pubkey, false), + AccountMeta::new_readonly(sysvar::rent::id(), false), + AccountMeta::new_readonly(sysvar::clock::id(), false), + AccountMeta::new_readonly(vote_init.node_pubkey, true), + ]; + + Instruction::new_with_bincode( + id(), + &VoteInstruction::InitializeAccountV2(*vote_init), + account_metas, + ) +} + + pub struct CreateVoteAccountConfig<'a> { pub space: u64, pub with_seed: Option<(&'a Pubkey, &'a str)>, @@ -311,6 +337,37 @@ pub fn create_account_with_config( vec![create_ix, init_ix] } +#[cfg(feature = "bincode")] +pub fn create_account_v2( + from_pubkey: &Pubkey, + vote_pubkey: &Pubkey, + vote_init: &VoteInitV2, + lamports: u64, + config: CreateVoteAccountConfig, +) -> Vec { + let create_ix = if let Some((base, seed)) = config.with_seed { + solana_system_interface::instruction::create_account_with_seed( + from_pubkey, + vote_pubkey, + base, + seed, + lamports, + config.space, + &id(), + ) + } else { + solana_system_interface::instruction::create_account( + from_pubkey, + vote_pubkey, + lamports, + config.space, + &id(), + ) + }; + let init_ix = initialize_account_v2(vote_pubkey, vote_init); + vec![create_ix, init_ix] +} + #[cfg(feature = "bincode")] pub fn authorize( vote_pubkey: &Pubkey, diff --git a/vote-interface/src/state/mod.rs b/vote-interface/src/state/mod.rs index c8e8fe512..35fec930b 100644 --- a/vote-interface/src/state/mod.rs +++ b/vote-interface/src/state/mod.rs @@ -33,6 +33,9 @@ pub(crate) mod vote_state_deserialize; /// Size of a BLS public key in a compressed point representation pub const BLS_PUBLIC_KEY_COMPRESSED_SIZE: usize = 48; +/// Size of a BLS signature in a compressed point representation +pub const BLS_SIGNATURE_COMPRESSED_SIZE: usize = 96; + // Maximum number of votes to keep around, tightly coupled with epoch_schedule::MINIMUM_SLOTS_PER_EPOCH pub const MAX_LOCKOUT_HISTORY: usize = 31; pub const INITIAL_LOCKOUT: usize = 2; diff --git a/vote-interface/src/state/vote_instruction_data.rs b/vote-interface/src/state/vote_instruction_data.rs index 136f2d71c..24e3510af 100644 --- a/vote-interface/src/state/vote_instruction_data.rs +++ b/vote-interface/src/state/vote_instruction_data.rs @@ -1,9 +1,13 @@ #[cfg(feature = "serde")] -use serde_derive::{Deserialize, Serialize}; +use { + serde_derive::{Deserialize, Serialize}, + serde_with::serde_as, +}; + #[cfg(feature = "frozen-abi")] use solana_frozen_abi_macro::{frozen_abi, AbiExample}; use { - crate::state::{Lockout, MAX_LOCKOUT_HISTORY}, + crate::state::{BLS_PUBLIC_KEY_COMPRESSED_SIZE, BLS_SIGNATURE_COMPRESSED_SIZE, Lockout, MAX_LOCKOUT_HISTORY}, solana_clock::{Slot, UnixTimestamp}, solana_hash::Hash, solana_pubkey::Pubkey, @@ -201,11 +205,53 @@ pub struct VoteInit { pub commission: u8, } +#[cfg_attr(feature = "serde", serde_as)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct VoteInitV2 { + pub node_pubkey: Pubkey, + pub authorized_voter: Pubkey, + #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] + pub authorized_voter_bls_pubkey: [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE], + #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] + pub authorized_voter_bls_proof_of_possession: [u8; BLS_SIGNATURE_COMPRESSED_SIZE], + pub authorized_withdrawer: Pubkey, + pub inflation_rewards_commission_bps: u16, + pub inflation_rewards_collector: Pubkey, + pub block_revenue_commission_bps: u16, + pub block_revenue_collector: Pubkey, +} + +impl Default for VoteInitV2 { + fn default() -> Self { + Self { + node_pubkey: Pubkey::default(), + authorized_voter: Pubkey::default(), + authorized_voter_bls_pubkey: [0u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE], + authorized_voter_bls_proof_of_possession: [0u8; BLS_SIGNATURE_COMPRESSED_SIZE], + authorized_withdrawer: Pubkey::default(), + inflation_rewards_commission_bps: 0, + inflation_rewards_collector: Pubkey::default(), + block_revenue_commission_bps: 0, + block_revenue_collector: Pubkey::default(), + } + } +} + +#[cfg_attr(feature = "serde", serde_as)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum VoteAuthorize { Voter, Withdrawer, + VoterWithBLS( + // BLS public key + #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] + [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE], + // BLS Proof of Possession + #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] + [u8; BLS_SIGNATURE_COMPRESSED_SIZE], + ) } #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] diff --git a/vote-interface/src/state/vote_state_v4.rs b/vote-interface/src/state/vote_state_v4.rs index 54a000992..c7d1b4d10 100644 --- a/vote-interface/src/state/vote_state_v4.rs +++ b/vote-interface/src/state/vote_state_v4.rs @@ -11,7 +11,7 @@ use solana_frozen_abi_macro::{frozen_abi, AbiExample}; #[cfg(any(target_os = "solana", feature = "bincode"))] use solana_instruction::error::InstructionError; use { - super::{BlockTimestamp, LandedVote, VoteInit, BLS_PUBLIC_KEY_COMPRESSED_SIZE}, + super::{BlockTimestamp, LandedVote, VoteInit, VoteInitV2, BLS_PUBLIC_KEY_COMPRESSED_SIZE}, crate::authorized_voters::AuthorizedVoters, solana_clock::{Clock, Epoch, Slot}, solana_pubkey::Pubkey, @@ -92,6 +92,20 @@ impl VoteStateV4 { } } + pub fn new_with_vote_init_v2(vote_init: &VoteInitV2, clock: &Clock) -> Self { + Self { + node_pubkey: vote_init.node_pubkey, + authorized_voters: AuthorizedVoters::new(clock.epoch, vote_init.authorized_voter), + bls_pubkey_compressed: Some(vote_init.authorized_voter_bls_pubkey), + authorized_withdrawer: vote_init.authorized_withdrawer, + inflation_rewards_commission_bps: vote_init.inflation_rewards_commission_bps, + inflation_rewards_collector: vote_init.inflation_rewards_collector, + block_revenue_commission_bps: vote_init.block_revenue_commission_bps, + block_revenue_collector: vote_init.block_revenue_collector, + ..Self::default() + } + } + #[cfg(any(target_os = "solana", feature = "bincode"))] pub fn deserialize(input: &[u8], vote_pubkey: &Pubkey) -> Result { let mut vote_state = Self::default(); From 058e39e82557373191344317490aa69931d733df Mon Sep 17 00:00:00 2001 From: Wen <113942165+wen-coding@users.noreply.github.com> Date: Mon, 3 Nov 2025 18:59:11 -0800 Subject: [PATCH 2/9] Make linter happy. --- vote-interface/src/instruction.rs | 1 - .../src/state/vote_instruction_data.rs | 17 +++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/vote-interface/src/instruction.rs b/vote-interface/src/instruction.rs index e4a0ec409..384f47c21 100644 --- a/vote-interface/src/instruction.rs +++ b/vote-interface/src/instruction.rs @@ -290,7 +290,6 @@ fn initialize_account_v2(vote_pubkey: &Pubkey, vote_init: &VoteInitV2) -> Instru ) } - pub struct CreateVoteAccountConfig<'a> { pub space: u64, pub with_seed: Option<(&'a Pubkey, &'a str)>, diff --git a/vote-interface/src/state/vote_instruction_data.rs b/vote-interface/src/state/vote_instruction_data.rs index 24e3510af..1298e924e 100644 --- a/vote-interface/src/state/vote_instruction_data.rs +++ b/vote-interface/src/state/vote_instruction_data.rs @@ -1,18 +1,19 @@ -#[cfg(feature = "serde")] -use { - serde_derive::{Deserialize, Serialize}, - serde_with::serde_as, -}; - #[cfg(feature = "frozen-abi")] use solana_frozen_abi_macro::{frozen_abi, AbiExample}; use { - crate::state::{BLS_PUBLIC_KEY_COMPRESSED_SIZE, BLS_SIGNATURE_COMPRESSED_SIZE, Lockout, MAX_LOCKOUT_HISTORY}, + crate::state::{ + Lockout, BLS_PUBLIC_KEY_COMPRESSED_SIZE, BLS_SIGNATURE_COMPRESSED_SIZE, MAX_LOCKOUT_HISTORY, + }, solana_clock::{Slot, UnixTimestamp}, solana_hash::Hash, solana_pubkey::Pubkey, std::{collections::VecDeque, fmt::Debug}, }; +#[cfg(feature = "serde")] +use { + serde_derive::{Deserialize, Serialize}, + serde_with::serde_as, +}; #[cfg_attr( feature = "frozen-abi", @@ -251,7 +252,7 @@ pub enum VoteAuthorize { // BLS Proof of Possession #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] [u8; BLS_SIGNATURE_COMPRESSED_SIZE], - ) + ), } #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] From 34945ff710001ed4b3e1278681c17a9eeb037f31 Mon Sep 17 00:00:00 2001 From: Wen <113942165+wen-coding@users.noreply.github.com> Date: Tue, 4 Nov 2025 08:33:03 -0800 Subject: [PATCH 3/9] Update vote-interface/src/instruction.rs Co-authored-by: Joe C --- vote-interface/src/instruction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vote-interface/src/instruction.rs b/vote-interface/src/instruction.rs index 384f47c21..3aa3852af 100644 --- a/vote-interface/src/instruction.rs +++ b/vote-interface/src/instruction.rs @@ -337,7 +337,7 @@ pub fn create_account_with_config( } #[cfg(feature = "bincode")] -pub fn create_account_v2( +pub fn create_account_with_config_v2( from_pubkey: &Pubkey, vote_pubkey: &Pubkey, vote_init: &VoteInitV2, From 45683561df758c50c33297220dd2328d30255c3e Mon Sep 17 00:00:00 2001 From: Wen <113942165+wen-coding@users.noreply.github.com> Date: Tue, 4 Nov 2025 12:32:04 -0800 Subject: [PATCH 4/9] Address pr comments. --- vote-interface/src/instruction.rs | 16 +++++++-------- .../src/state/vote_instruction_data.rs | 20 +++++++++++-------- vote-interface/src/state/vote_state_v4.rs | 4 ++-- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/vote-interface/src/instruction.rs b/vote-interface/src/instruction.rs index 3aa3852af..b87dc79a5 100644 --- a/vote-interface/src/instruction.rs +++ b/vote-interface/src/instruction.rs @@ -34,15 +34,6 @@ pub enum VoteInstruction { /// 3. `[SIGNER]` New validator identity (node_pubkey) InitializeAccount(VoteInit), - // Initialize a vote account using VoteInitV2 - /// - /// # Account references - /// 0. `[WRITE]` Uninitialized vote account - /// 1. `[]` Rent sysvar - /// 2. `[]` Clock sysvar - /// 3. `[SIGNER]` New validator identity (node_pubkey) - InitializeAccountV2(VoteInitV2), - /// Authorize a key to send votes or issue a withdrawal /// /// # Account references @@ -178,6 +169,13 @@ pub enum VoteInstruction { #[cfg_attr(feature = "serde", serde(with = "serde_tower_sync"))] TowerSync, Hash, ), + + // Initialize a vote account using VoteInitV2 + /// + /// # Account references + /// 0. `[WRITE]` Uninitialized vote account + /// 1. `[SIGNER]` New validator identity (node_pubkey) + InitializeAccountV2(VoteInitV2), } impl VoteInstruction { diff --git a/vote-interface/src/state/vote_instruction_data.rs b/vote-interface/src/state/vote_instruction_data.rs index 1298e924e..00b4af320 100644 --- a/vote-interface/src/state/vote_instruction_data.rs +++ b/vote-interface/src/state/vote_instruction_data.rs @@ -239,20 +239,24 @@ impl Default for VoteInitV2 { } } +#[cfg_attr(feature = "serde", serde_as)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct VoterWithBLSArgs { + #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] + bls_pub_key: [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE], + + #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] + bls_proof_of_possession: [u8; BLS_SIGNATURE_COMPRESSED_SIZE], +} + #[cfg_attr(feature = "serde", serde_as)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum VoteAuthorize { Voter, Withdrawer, - VoterWithBLS( - // BLS public key - #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] - [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE], - // BLS Proof of Possession - #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] - [u8; BLS_SIGNATURE_COMPRESSED_SIZE], - ), + VoterWithBLS(VoterWithBLSArgs), } #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] diff --git a/vote-interface/src/state/vote_state_v4.rs b/vote-interface/src/state/vote_state_v4.rs index c7d1b4d10..101c41e3d 100644 --- a/vote-interface/src/state/vote_state_v4.rs +++ b/vote-interface/src/state/vote_state_v4.rs @@ -77,7 +77,7 @@ impl VoteStateV4 { 3762 // Same size as V3 to avoid account resizing } - pub fn new(vote_pubkey: &Pubkey, vote_init: &VoteInit, clock: &Clock) -> Self { + pub fn new_with_defaults(vote_pubkey: &Pubkey, vote_init: &VoteInit, clock: &Clock) -> Self { Self { node_pubkey: vote_init.node_pubkey, authorized_voters: AuthorizedVoters::new(clock.epoch, vote_init.authorized_voter), @@ -92,7 +92,7 @@ impl VoteStateV4 { } } - pub fn new_with_vote_init_v2(vote_init: &VoteInitV2, clock: &Clock) -> Self { + pub fn new(vote_init: &VoteInitV2, clock: &Clock) -> Self { Self { node_pubkey: vote_init.node_pubkey, authorized_voters: AuthorizedVoters::new(clock.epoch, vote_init.authorized_voter), From 7b86969ba6bca1e4ce73ef17d6902a348407d597 Mon Sep 17 00:00:00 2001 From: Wen <113942165+wen-coding@users.noreply.github.com> Date: Tue, 4 Nov 2025 20:37:06 -0800 Subject: [PATCH 5/9] Address pr comments. --- .../src/state/vote_instruction_data.rs | 72 ++++++++++--------- vote-interface/src/state/vote_state_v4.rs | 2 +- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/vote-interface/src/state/vote_instruction_data.rs b/vote-interface/src/state/vote_instruction_data.rs index 00b4af320..2bc33e853 100644 --- a/vote-interface/src/state/vote_instruction_data.rs +++ b/vote-interface/src/state/vote_instruction_data.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "serde")] +use serde_derive::{Deserialize, Serialize}; #[cfg(feature = "frozen-abi")] use solana_frozen_abi_macro::{frozen_abi, AbiExample}; use { @@ -9,11 +11,6 @@ use { solana_pubkey::Pubkey, std::{collections::VecDeque, fmt::Debug}, }; -#[cfg(feature = "serde")] -use { - serde_derive::{Deserialize, Serialize}, - serde_with::serde_as, -}; #[cfg_attr( feature = "frozen-abi", @@ -206,16 +203,44 @@ pub struct VoteInit { pub commission: u8, } -#[cfg_attr(feature = "serde", serde_as)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct BLSPubkeyCompressed( + #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] + [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE], +); + +impl Default for BLSPubkeyCompressed { + fn default() -> Self { + Self([0u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE]) + } +} + +impl From for [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE] { + fn from(wrapper: BLSPubkeyCompressed) -> Self { + wrapper.0 + } +} + +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct BLSSignatureCompressed( + #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] [u8; BLS_SIGNATURE_COMPRESSED_SIZE], +); + +impl Default for BLSSignatureCompressed { + fn default() -> Self { + Self([0u8; BLS_SIGNATURE_COMPRESSED_SIZE]) + } +} + +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)] pub struct VoteInitV2 { pub node_pubkey: Pubkey, pub authorized_voter: Pubkey, - #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] - pub authorized_voter_bls_pubkey: [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE], - #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] - pub authorized_voter_bls_proof_of_possession: [u8; BLS_SIGNATURE_COMPRESSED_SIZE], + pub authorized_voter_bls_pubkey: BLSPubkeyCompressed, + pub authorized_voter_bls_proof_of_possession: BLSSignatureCompressed, pub authorized_withdrawer: Pubkey, pub inflation_rewards_commission_bps: u16, pub inflation_rewards_collector: Pubkey, @@ -223,34 +248,13 @@ pub struct VoteInitV2 { pub block_revenue_collector: Pubkey, } -impl Default for VoteInitV2 { - fn default() -> Self { - Self { - node_pubkey: Pubkey::default(), - authorized_voter: Pubkey::default(), - authorized_voter_bls_pubkey: [0u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE], - authorized_voter_bls_proof_of_possession: [0u8; BLS_SIGNATURE_COMPRESSED_SIZE], - authorized_withdrawer: Pubkey::default(), - inflation_rewards_commission_bps: 0, - inflation_rewards_collector: Pubkey::default(), - block_revenue_commission_bps: 0, - block_revenue_collector: Pubkey::default(), - } - } -} - -#[cfg_attr(feature = "serde", serde_as)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)] pub struct VoterWithBLSArgs { - #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] - bls_pub_key: [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE], - - #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] - bls_proof_of_possession: [u8; BLS_SIGNATURE_COMPRESSED_SIZE], + bls_pub_key: BLSPubkeyCompressed, + bls_proof_of_possession: BLSSignatureCompressed, } -#[cfg_attr(feature = "serde", serde_as)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum VoteAuthorize { diff --git a/vote-interface/src/state/vote_state_v4.rs b/vote-interface/src/state/vote_state_v4.rs index 101c41e3d..61f22c0df 100644 --- a/vote-interface/src/state/vote_state_v4.rs +++ b/vote-interface/src/state/vote_state_v4.rs @@ -96,7 +96,7 @@ impl VoteStateV4 { Self { node_pubkey: vote_init.node_pubkey, authorized_voters: AuthorizedVoters::new(clock.epoch, vote_init.authorized_voter), - bls_pubkey_compressed: Some(vote_init.authorized_voter_bls_pubkey), + bls_pubkey_compressed: Some(vote_init.authorized_voter_bls_pubkey.into()), authorized_withdrawer: vote_init.authorized_withdrawer, inflation_rewards_commission_bps: vote_init.inflation_rewards_commission_bps, inflation_rewards_collector: vote_init.inflation_rewards_collector, From 8e67cc5a5aaea67e1dcb373596f37b449b0270ef Mon Sep 17 00:00:00 2001 From: Wen <113942165+wen-coding@users.noreply.github.com> Date: Tue, 4 Nov 2025 20:40:17 -0800 Subject: [PATCH 6/9] Remove the not required sysvar accounts. --- vote-interface/src/instruction.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/vote-interface/src/instruction.rs b/vote-interface/src/instruction.rs index b87dc79a5..bb25c0856 100644 --- a/vote-interface/src/instruction.rs +++ b/vote-interface/src/instruction.rs @@ -276,8 +276,6 @@ fn initialize_account(vote_pubkey: &Pubkey, vote_init: &VoteInit) -> Instruction fn initialize_account_v2(vote_pubkey: &Pubkey, vote_init: &VoteInitV2) -> Instruction { let account_metas = vec![ AccountMeta::new(*vote_pubkey, false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - AccountMeta::new_readonly(sysvar::clock::id(), false), AccountMeta::new_readonly(vote_init.node_pubkey, true), ]; From d91a7b66ee3d4f5527bb93009a5f22f3827bfbed Mon Sep 17 00:00:00 2001 From: Wen <113942165+wen-coding@users.noreply.github.com> Date: Tue, 18 Nov 2025 14:16:03 -0800 Subject: [PATCH 7/9] Address pr comments. --- Cargo.lock | 1 - vote-interface/Cargo.toml | 2 - vote-interface/src/instruction.rs | 14 ++++ .../src/state/vote_instruction_data.rs | 77 ++++++++++--------- 4 files changed, 54 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 70851410c..ef0926186 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3989,7 +3989,6 @@ dependencies = [ "num-traits", "rand", "serde", - "serde_bytes", "serde_derive", "serde_with", "solana-clock", diff --git a/vote-interface/Cargo.toml b/vote-interface/Cargo.toml index 36175014a..f127b968d 100644 --- a/vote-interface/Cargo.toml +++ b/vote-interface/Cargo.toml @@ -38,7 +38,6 @@ frozen-abi = [ serde = [ "dep:cfg_eval", "dep:serde", - "dep:serde_bytes", "dep:serde_derive", "dep:serde_with", "dep:solana-serde-varint", @@ -55,7 +54,6 @@ cfg_eval = { workspace = true, optional = true } num-derive = { workspace = true } num-traits = { workspace = true } serde = { workspace = true, optional = true } -serde_bytes = { workspace = true, optional = true } serde_derive = { workspace = true, optional = true } serde_with = { workspace = true, features = ["macros"], optional = true } solana-clock = { workspace = true } diff --git a/vote-interface/src/instruction.rs b/vote-interface/src/instruction.rs index bb25c0856..3013ec486 100644 --- a/vote-interface/src/instruction.rs +++ b/vote-interface/src/instruction.rs @@ -40,6 +40,9 @@ pub enum VoteInstruction { /// 0. `[WRITE]` Vote account to be updated with the Pubkey for authorization /// 1. `[]` Clock sysvar /// 2. `[SIGNER]` Vote or withdraw authority + /// + /// When SIMD-0387 is enabled, the `VoteAuthorize::Voter` variant is + /// disallowed for any vote accounts whose BLS pubkey is set to `Some`. Authorize(Pubkey, VoteAuthorize), /// A Vote instruction with recent votes @@ -93,6 +96,9 @@ pub enum VoteInstruction { /// 1. `[]` Clock sysvar /// 2. `[SIGNER]` Vote or withdraw authority /// 3. `[SIGNER]` New vote or withdraw authority + /// + /// When SIMD-0387 is enabled, the `VoteAuthorize::Voter` variant is + /// disallowed for any vote accounts whose BLS pubkey is set to `Some`. AuthorizeChecked(VoteAuthorize), /// Update the onchain vote state for the signer. @@ -117,6 +123,10 @@ pub enum VoteInstruction { /// 0. `[Write]` Vote account to be updated /// 1. `[]` Clock sysvar /// 2. `[SIGNER]` Base key of current Voter or Withdrawer authority's derived key + /// + /// When SIMD-0387 is enabled, the `VoteAuthorize::Voter` variant in + /// `authorization_type` is disallowed for any vote accounts whose BLS + /// pubkey is set to `Some`. AuthorizeWithSeed(VoteAuthorizeWithSeedArgs), /// Given that the current Voter or Withdrawer authority is a derived key, @@ -131,6 +141,10 @@ pub enum VoteInstruction { /// 1. `[]` Clock sysvar /// 2. `[SIGNER]` Base key of current Voter or Withdrawer authority's derived key /// 3. `[SIGNER]` New vote or withdraw authority + /// + /// When SIMD-0387 is enabled, the `VoteAuthorize::Voter` variant in + /// `authorization_type` is disallowed for any vote accounts whose BLS + /// pubkey is set to `Some`. AuthorizeCheckedWithSeed(VoteAuthorizeCheckedWithSeedArgs), /// Update the onchain vote state for the signer. diff --git a/vote-interface/src/state/vote_instruction_data.rs b/vote-interface/src/state/vote_instruction_data.rs index 2bc33e853..933048bf7 100644 --- a/vote-interface/src/state/vote_instruction_data.rs +++ b/vote-interface/src/state/vote_instruction_data.rs @@ -1,5 +1,8 @@ #[cfg(feature = "serde")] -use serde_derive::{Deserialize, Serialize}; +use { + serde_derive::{Deserialize, Serialize}, + serde_with::serde_as, +}; #[cfg(feature = "frozen-abi")] use solana_frozen_abi_macro::{frozen_abi, AbiExample}; use { @@ -203,44 +206,16 @@ pub struct VoteInit { pub commission: u8, } +#[cfg_attr(feature = "serde", cfg_eval::cfg_eval, serde_as)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub struct BLSPubkeyCompressed( - #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] - [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE], -); - -impl Default for BLSPubkeyCompressed { - fn default() -> Self { - Self([0u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE]) - } -} - -impl From for [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE] { - fn from(wrapper: BLSPubkeyCompressed) -> Self { - wrapper.0 - } -} - -#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub struct BLSSignatureCompressed( - #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] [u8; BLS_SIGNATURE_COMPRESSED_SIZE], -); - -impl Default for BLSSignatureCompressed { - fn default() -> Self { - Self([0u8; BLS_SIGNATURE_COMPRESSED_SIZE]) - } -} - -#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] -#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)] pub struct VoteInitV2 { pub node_pubkey: Pubkey, pub authorized_voter: Pubkey, - pub authorized_voter_bls_pubkey: BLSPubkeyCompressed, - pub authorized_voter_bls_proof_of_possession: BLSSignatureCompressed, + #[cfg_attr(feature = "serde", serde_as(as = "[_; BLS_PUBLIC_KEY_COMPRESSED_SIZE]"))] + pub authorized_voter_bls_pubkey: [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE], + #[cfg_attr(feature = "serde", serde_as(as = "[_; BLS_SIGNATURE_COMPRESSED_SIZE]"))] + pub authorized_voter_bls_proof_of_possession: [u8; BLS_SIGNATURE_COMPRESSED_SIZE], pub authorized_withdrawer: Pubkey, pub inflation_rewards_commission_bps: u16, pub inflation_rewards_collector: Pubkey, @@ -248,11 +223,39 @@ pub struct VoteInitV2 { pub block_revenue_collector: Pubkey, } +impl Default for VoteInitV2 { + fn default() -> Self { + Self { + node_pubkey: Pubkey::default(), + authorized_voter: Pubkey::default(), + authorized_voter_bls_pubkey: [0u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE], + authorized_voter_bls_proof_of_possession: [0u8; BLS_SIGNATURE_COMPRESSED_SIZE], + authorized_withdrawer: Pubkey::default(), + inflation_rewards_commission_bps: 0, + inflation_rewards_collector: Pubkey::default(), + block_revenue_commission_bps: 0, + block_revenue_collector: Pubkey::default(), + } + } +} + +#[cfg_attr(feature = "serde", cfg_eval::cfg_eval, serde_as)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] -#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct VoterWithBLSArgs { - bls_pub_key: BLSPubkeyCompressed, - bls_proof_of_possession: BLSSignatureCompressed, + #[cfg_attr(feature = "serde", serde_as(as = "[_; BLS_PUBLIC_KEY_COMPRESSED_SIZE]"))] + pub bls_pub_key: [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE], + #[cfg_attr(feature = "serde", serde_as(as = "[_; BLS_SIGNATURE_COMPRESSED_SIZE]"))] + pub bls_proof_of_possession: [u8; BLS_SIGNATURE_COMPRESSED_SIZE], +} + +impl Default for VoterWithBLSArgs { + fn default() -> Self { + Self { + bls_pub_key: [0u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE], + bls_proof_of_possession: [0u8; BLS_SIGNATURE_COMPRESSED_SIZE], + } + } } #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] From 34d2074eae16fd25d5e8a4b26b70b7bf5b473ad9 Mon Sep 17 00:00:00 2001 From: Wen <113942165+wen-coding@users.noreply.github.com> Date: Tue, 18 Nov 2025 14:17:29 -0800 Subject: [PATCH 8/9] Make linter happy. --- vote-interface/src/state/vote_instruction_data.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vote-interface/src/state/vote_instruction_data.rs b/vote-interface/src/state/vote_instruction_data.rs index 933048bf7..522da458c 100644 --- a/vote-interface/src/state/vote_instruction_data.rs +++ b/vote-interface/src/state/vote_instruction_data.rs @@ -213,7 +213,7 @@ pub struct VoteInitV2 { pub node_pubkey: Pubkey, pub authorized_voter: Pubkey, #[cfg_attr(feature = "serde", serde_as(as = "[_; BLS_PUBLIC_KEY_COMPRESSED_SIZE]"))] - pub authorized_voter_bls_pubkey: [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE], + pub authorized_voter_bls_pubkey: [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE], #[cfg_attr(feature = "serde", serde_as(as = "[_; BLS_SIGNATURE_COMPRESSED_SIZE]"))] pub authorized_voter_bls_proof_of_possession: [u8; BLS_SIGNATURE_COMPRESSED_SIZE], pub authorized_withdrawer: Pubkey, From a908ffe91b6d08b44db8aa7680b00406aa6e94b7 Mon Sep 17 00:00:00 2001 From: Wen <113942165+wen-coding@users.noreply.github.com> Date: Tue, 18 Nov 2025 14:19:48 -0800 Subject: [PATCH 9/9] Make linter happy. --- .../src/state/vote_instruction_data.rs | 20 ++++++++++++------- vote-interface/src/state/vote_state_v4.rs | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/vote-interface/src/state/vote_instruction_data.rs b/vote-interface/src/state/vote_instruction_data.rs index 522da458c..3d214e1dc 100644 --- a/vote-interface/src/state/vote_instruction_data.rs +++ b/vote-interface/src/state/vote_instruction_data.rs @@ -1,8 +1,3 @@ -#[cfg(feature = "serde")] -use { - serde_derive::{Deserialize, Serialize}, - serde_with::serde_as, -}; #[cfg(feature = "frozen-abi")] use solana_frozen_abi_macro::{frozen_abi, AbiExample}; use { @@ -14,6 +9,11 @@ use { solana_pubkey::Pubkey, std::{collections::VecDeque, fmt::Debug}, }; +#[cfg(feature = "serde")] +use { + serde_derive::{Deserialize, Serialize}, + serde_with::serde_as, +}; #[cfg_attr( feature = "frozen-abi", @@ -212,7 +212,10 @@ pub struct VoteInit { pub struct VoteInitV2 { pub node_pubkey: Pubkey, pub authorized_voter: Pubkey, - #[cfg_attr(feature = "serde", serde_as(as = "[_; BLS_PUBLIC_KEY_COMPRESSED_SIZE]"))] + #[cfg_attr( + feature = "serde", + serde_as(as = "[_; BLS_PUBLIC_KEY_COMPRESSED_SIZE]") + )] pub authorized_voter_bls_pubkey: [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE], #[cfg_attr(feature = "serde", serde_as(as = "[_; BLS_SIGNATURE_COMPRESSED_SIZE]"))] pub authorized_voter_bls_proof_of_possession: [u8; BLS_SIGNATURE_COMPRESSED_SIZE], @@ -243,7 +246,10 @@ impl Default for VoteInitV2 { #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct VoterWithBLSArgs { - #[cfg_attr(feature = "serde", serde_as(as = "[_; BLS_PUBLIC_KEY_COMPRESSED_SIZE]"))] + #[cfg_attr( + feature = "serde", + serde_as(as = "[_; BLS_PUBLIC_KEY_COMPRESSED_SIZE]") + )] pub bls_pub_key: [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE], #[cfg_attr(feature = "serde", serde_as(as = "[_; BLS_SIGNATURE_COMPRESSED_SIZE]"))] pub bls_proof_of_possession: [u8; BLS_SIGNATURE_COMPRESSED_SIZE], diff --git a/vote-interface/src/state/vote_state_v4.rs b/vote-interface/src/state/vote_state_v4.rs index 61f22c0df..101c41e3d 100644 --- a/vote-interface/src/state/vote_state_v4.rs +++ b/vote-interface/src/state/vote_state_v4.rs @@ -96,7 +96,7 @@ impl VoteStateV4 { Self { node_pubkey: vote_init.node_pubkey, authorized_voters: AuthorizedVoters::new(clock.epoch, vote_init.authorized_voter), - bls_pubkey_compressed: Some(vote_init.authorized_voter_bls_pubkey.into()), + bls_pubkey_compressed: Some(vote_init.authorized_voter_bls_pubkey), authorized_withdrawer: vote_init.authorized_withdrawer, inflation_rewards_commission_bps: vote_init.inflation_rewards_commission_bps, inflation_rewards_collector: vote_init.inflation_rewards_collector,