Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 67 additions & 1 deletion vote-interface/src/instruction.rs
Comment thread
buffalojoec marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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,
Expand All @@ -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.
Expand Down Expand Up @@ -169,6 +183,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 {
Expand Down Expand Up @@ -265,6 +286,20 @@ 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(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)>,
Expand Down Expand Up @@ -311,6 +346,37 @@ pub fn create_account_with_config(
vec![create_ix, init_ix]
}

#[cfg(feature = "bincode")]
pub fn create_account_with_config_v2(
from_pubkey: &Pubkey,
vote_pubkey: &Pubkey,
vote_init: &VoteInitV2,
lamports: u64,
config: CreateVoteAccountConfig,
) -> Vec<Instruction> {
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,
Expand Down
3 changes: 3 additions & 0 deletions vote-interface/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
70 changes: 67 additions & 3 deletions vote-interface/src/state/vote_instruction_data.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
#[cfg(feature = "serde")]
use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "frozen-abi")]
use solana_frozen_abi_macro::{frozen_abi, AbiExample};
use {
crate::state::{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",
Expand Down Expand Up @@ -201,11 +206,70 @@ 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 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],
#[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,
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", cfg_eval::cfg_eval, serde_as)]
#[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]")
)]
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],
}
}
}
Comment on lines +258 to +265
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this could also get similar Default treatment as the other struct, by deriving it from newtypes instead of doing it by hand

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean I should use a wrapper here?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's what I was getting at, but it looks like the final decision was to not use wrapper structs, so no need to do anything here


#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum VoteAuthorize {
Voter,
Withdrawer,
VoterWithBLS(VoterWithBLSArgs),
}

#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
Expand Down
18 changes: 16 additions & 2 deletions vote-interface/src/state/vote_state_v4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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),
Expand All @@ -92,6 +92,20 @@ impl VoteStateV4 {
}
}

pub fn new(vote_init: &VoteInitV2, clock: &Clock) -> Self {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how this is being used downstream already or how the transition is being planned, but was this breaking change intended?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok great, thanks! Sorry for the noise then

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<Self, InstructionError> {
let mut vote_state = Self::default();
Expand Down