Skip to content

Commit

Permalink
feat: adds voting cluster authority sigs
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinrodriguez-io committed Oct 16, 2024
1 parent 5ab9e26 commit 1e02135
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 11 deletions.
5 changes: 5 additions & 0 deletions cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ pub enum CliCommand {
memo: Option<String>,
fee_payer: SignerIndex,
compute_unit_price: Option<u64>,
cluster_authority: SignerIndex,
},
ShowVoteAccount {
pubkey: Pubkey,
Expand Down Expand Up @@ -1475,6 +1476,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
memo,
fee_payer,
compute_unit_price,
cluster_authority,
} => process_create_vote_account(
&rpc_client,
config,
Expand All @@ -1492,6 +1494,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
memo.as_ref(),
*fee_payer,
*compute_unit_price,
*cluster_authority,
),
CliCommand::ShowVoteAccount {
pubkey: vote_account_pubkey,
Expand Down Expand Up @@ -2139,6 +2142,7 @@ mod tests {
memo: None,
fee_payer: 0,
compute_unit_price: None,
cluster_authority: 3,
};
config.signers = vec![&keypair, &bob_keypair, &identity_keypair];
let result = process_command(&config);
Expand Down Expand Up @@ -2398,6 +2402,7 @@ mod tests {
memo: None,
fee_payer: 0,
compute_unit_price: None,
cluster_authority: 3,
};
config.signers = vec![&keypair, &bob_keypair, &identity_keypair];
assert!(process_command(&config).is_err());
Expand Down
15 changes: 12 additions & 3 deletions cli/src/vote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@ use {
solana_rpc_client_api::config::RpcGetVoteAccountsConfig,
solana_rpc_client_nonce_utils::blockhash_query::BlockhashQuery,
solana_sdk::{
account::Account, commitment_config::CommitmentConfig, message::Message,
native_token::lamports_to_sol, pubkey::Pubkey, system_instruction::SystemError,
transaction::Transaction,
account::Account, commitment_config::CommitmentConfig, message::Message, native_token::lamports_to_sol, pubkey::Pubkey, signer::Signer, system_instruction::SystemError, transaction::Transaction
},
solana_vote_program::{
vote_error::VoteError,
Expand Down Expand Up @@ -456,6 +454,8 @@ pub fn parse_create_vote_account(
let seed = matches.value_of("seed").map(|s| s.to_string());
let (identity_account, identity_pubkey) =
signer_of(matches, "identity_account", wallet_manager)?;
let (cluster_authority, cluster_authority_pubkey) =
signer_of(matches, "cluster_authority", wallet_manager)?;
let commission = value_t_or_exit!(matches, "commission", u8);
let authorized_voter = pubkey_of_signer(matches, "authorized_voter", wallet_manager)?;
let authorized_withdrawer =
Expand Down Expand Up @@ -511,6 +511,7 @@ pub fn parse_create_vote_account(
memo,
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
compute_unit_price,
cluster_authority: signer_info.index_of(cluster_authority_pubkey).unwrap(),
},
signers: signer_info.signers,
})
Expand Down Expand Up @@ -804,6 +805,7 @@ pub fn process_create_vote_account(
memo: Option<&String>,
fee_payer: SignerIndex,
compute_unit_price: Option<u64>,
cluster_authority: SignerIndex,
) -> ProcessResult {
let vote_account = config.signers[vote_account];
let vote_account_pubkey = vote_account.pubkey();
Expand Down Expand Up @@ -856,6 +858,7 @@ pub fn process_create_vote_account(
};

let ixs = vote_instruction::create_account_with_config(
&config.signers[cluster_authority].pubkey(),
&config.signers[0].pubkey(),
to,
&vote_init,
Expand Down Expand Up @@ -1816,6 +1819,7 @@ mod tests {
memo: None,
fee_payer: 0,
compute_unit_price: None,
cluster_authority: 3,
},
signers: vec![
Box::new(read_keypair_file(&default_keypair_file).unwrap()),
Expand Down Expand Up @@ -1850,6 +1854,7 @@ mod tests {
memo: None,
fee_payer: 0,
compute_unit_price: None,
cluster_authority: 3,
},
signers: vec![
Box::new(read_keypair_file(&default_keypair_file).unwrap()),
Expand Down Expand Up @@ -1891,6 +1896,7 @@ mod tests {
memo: None,
fee_payer: 0,
compute_unit_price: None,
cluster_authority: 3,
},
signers: vec![
Box::new(read_keypair_file(&default_keypair_file).unwrap()),
Expand Down Expand Up @@ -1944,6 +1950,7 @@ mod tests {
memo: None,
fee_payer: 0,
compute_unit_price: None,
cluster_authority: 3,
},
signers: vec![
Box::new(read_keypair_file(&default_keypair_file).unwrap()),
Expand Down Expand Up @@ -1987,6 +1994,7 @@ mod tests {
memo: None,
fee_payer: 0,
compute_unit_price: None,
cluster_authority: 3,
},
signers: vec![
Box::new(read_keypair_file(&default_keypair_file).unwrap()),
Expand Down Expand Up @@ -2026,6 +2034,7 @@ mod tests {
memo: None,
fee_payer: 0,
compute_unit_price: None,
cluster_authority: 3,
},
signers: vec![
Box::new(read_keypair_file(&default_keypair_file).unwrap()),
Expand Down
3 changes: 3 additions & 0 deletions ledger/src/staking_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ pub(crate) mod tests {
vote_account: &Keypair,
validator_identity_account: &Keypair,
amount: u64,
cluster_authority: &Keypair,
) {
let vote_pubkey = vote_account.pubkey();
let cluster_authority_pubkey = cluster_authority.pubkey();
fn process_instructions<T: Signers>(bank: &Bank, keypairs: &T, ixs: &[Instruction]) {
let tx = Transaction::new_signed_with_payer(
ixs,
Expand All @@ -45,6 +47,7 @@ pub(crate) mod tests {
bank,
&[from_account, vote_account, validator_identity_account],
&vote_instruction::create_account_with_config(
&cluster_authority_pubkey,
&from_account.pubkey(),
&vote_pubkey,
&VoteInit {
Expand Down
19 changes: 18 additions & 1 deletion local-cluster/src/local_cluster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ impl LocalCluster {
cluster_lamports: u64,
lamports_per_node: u64,
socket_addr_space: SocketAddrSpace,
cluster_authority_keypair: Arc<Keypair>,
) -> Self {
Self::new(
&mut ClusterConfig::new_with_equal_stakes(
Expand All @@ -163,6 +164,7 @@ impl LocalCluster {
lamports_per_node,
),
socket_addr_space,
cluster_authority_keypair,
)
}

Expand All @@ -187,7 +189,11 @@ impl LocalCluster {
}
}

pub fn new(config: &mut ClusterConfig, socket_addr_space: SocketAddrSpace) -> Self {
pub fn new(
config: &mut ClusterConfig,
socket_addr_space: SocketAddrSpace,
cluster_authority_keypair: Arc<Keypair>,
) -> Self {
assert_eq!(config.validator_configs.len(), config.node_stakes.len());

let connection_cache = if config.tpu_use_quic {
Expand Down Expand Up @@ -391,6 +397,7 @@ impl LocalCluster {
key.clone(),
node_pubkey_to_vote_key.get(&key.pubkey()).cloned(),
socket_addr_space,
cluster_authority_keypair,
);
}

Expand All @@ -402,6 +409,7 @@ impl LocalCluster {
0,
Arc::new(Keypair::new()),
None,
cluster_authority_keypair.clone(),
socket_addr_space,
);
});
Expand Down Expand Up @@ -447,6 +455,7 @@ impl LocalCluster {
stake: u64,
validator_keypair: Arc<Keypair>,
voting_keypair: Option<Arc<Keypair>>,
cluster_authority_keypair: Arc<Keypair>,
socket_addr_space: SocketAddrSpace,
) -> Pubkey {
self.do_add_validator(
Expand All @@ -455,6 +464,7 @@ impl LocalCluster {
stake,
validator_keypair,
voting_keypair,
cluster_authority_keypair,
socket_addr_space,
)
}
Expand All @@ -467,13 +477,15 @@ impl LocalCluster {
validator_keypair: Arc<Keypair>,
voting_keypair: Option<Arc<Keypair>>,
socket_addr_space: SocketAddrSpace,
cluster_authority_keypair: Arc<Keypair>,
) -> Pubkey {
self.do_add_validator(
validator_config,
false,
stake,
validator_keypair,
voting_keypair,
cluster_authority_keypair,
socket_addr_space,
)
}
Expand All @@ -485,6 +497,7 @@ impl LocalCluster {
stake: u64,
validator_keypair: Arc<Keypair>,
mut voting_keypair: Option<Arc<Keypair>>,
cluster_authority_keypair: Arc<Keypair>,
socket_addr_space: SocketAddrSpace,
) -> Pubkey {
let client = self.build_tpu_quic_client().expect("tpu_client");
Expand Down Expand Up @@ -520,6 +533,7 @@ impl LocalCluster {
Self::setup_vote_and_stake_accounts(
&client,
voting_keypair.as_ref().unwrap(),
&cluster_authority_keypair,
&validator_keypair,
stake,
)
Expand Down Expand Up @@ -757,10 +771,12 @@ impl LocalCluster {
fn setup_vote_and_stake_accounts(
client: &QuicTpuClient,
vote_account: &Keypair,
cluster_authority_keypair: &Keypair,
from_account: &Arc<Keypair>,
amount: u64,
) -> Result<()> {
let vote_account_pubkey = vote_account.pubkey();
let cluster_authority_pubkey = cluster_authority_keypair.pubkey();
let node_pubkey = from_account.pubkey();
info!(
"setup_vote_and_stake_accounts: {}, {}, amount: {}",
Expand All @@ -778,6 +794,7 @@ impl LocalCluster {
{
// 1) Create vote account
let instructions = vote_instruction::create_account_with_config(
&cluster_authority_pubkey,
&from_account.pubkey(),
&vote_account_pubkey,
&VoteInit {
Expand Down
39 changes: 34 additions & 5 deletions programs/vote/src/vote_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@ use {
sysvar_cache::get_sysvar_with_account_check,
},
solana_sdk::{
instruction::InstructionError,
program_utils::limited_deserialize,
pubkey::Pubkey,
transaction_context::{BorrowedAccount, InstructionContext, TransactionContext},
account::ReadableAccount, instruction::InstructionError, program_utils::limited_deserialize, pubkey::Pubkey, system_program, transaction_context::{BorrowedAccount, InstructionContext, TransactionContext}
},
std::collections::HashSet,
};
Expand Down Expand Up @@ -74,7 +71,34 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context|
}
let clock =
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?;
vote_state::initialize_account(&mut me, &vote_init, &signers, &clock)

// Account 3 is AUTH1111111111111111111111111111111111111111
// Which contains the cluster authority pubkey bytes.
let auth_account = invoke_context.transaction_context.get_account_at_index(3)?;
let auth_account_key = invoke_context
.transaction_context
.get_key_of_account_at_index(3)?;
if auth_account_key
!= &solana_program::pubkey!("AUTH1111111111111111111111111111111111111111")
{
return Err(InstructionError::MissingAccount);
}
let auth_account = auth_account.borrow();
if auth_account.owner() != &system_program::ID {
return Err(InstructionError::InvalidAccountOwner);
}
let authorized_signer = auth_account.deserialize_data::<Pubkey>();
if let Err(_) = authorized_signer {
return Err(InstructionError::InvalidArgument);
}

vote_state::initialize_account(
&mut me,
&vote_init,
&signers,
&clock,
&authorized_signer.unwrap(),
)
}
VoteInstruction::Authorize(voter_pubkey, vote_authorize) => {
let clock =
Expand Down Expand Up @@ -1764,9 +1788,11 @@ mod tests {

#[test]
fn test_create_account_vote_state_1_14_11() {
let cluster_authority = Pubkey::new_unique();
let node_pubkey = Pubkey::new_unique();
let vote_pubkey = Pubkey::new_unique();
let instructions = create_account_with_config(
&cluster_authority,
&node_pubkey,
&vote_pubkey,
&VoteInit {
Expand Down Expand Up @@ -1802,9 +1828,11 @@ mod tests {

#[test]
fn test_create_account_vote_state_current() {
let cluster_authority = Pubkey::new_unique();
let node_pubkey = Pubkey::new_unique();
let vote_pubkey = Pubkey::new_unique();
let instructions = create_account_with_config(
&cluster_authority,
&node_pubkey,
&vote_pubkey,
&VoteInit {
Expand Down Expand Up @@ -1844,6 +1872,7 @@ mod tests {
fn test_vote_process_instruction() {
solana_logger::setup();
let instructions = create_account_with_config(
&Pubkey::new_unique(),
&Pubkey::new_unique(),
&Pubkey::new_unique(),
&VoteInit::default(),
Expand Down
5 changes: 5 additions & 0 deletions programs/vote/src/vote_state/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Vote state, vote program
//! Receive and processes votes from validators
pub use solana_program::vote::state::{vote_state_versions::*, *};
use solana_sdk::pubkey;
use {
log::*,
serde_derive::{Deserialize, Serialize},
Expand Down Expand Up @@ -1031,6 +1032,7 @@ pub fn initialize_account<S: std::hash::BuildHasher>(
vote_init: &VoteInit,
signers: &HashSet<Pubkey, S>,
clock: &Clock,
cluster_authority_signer: &Pubkey,
) -> Result<(), InstructionError> {
if vote_account.get_data().len() != VoteStateVersions::vote_state_size_of(true) {
return Err(InstructionError::InvalidAccountData);
Expand All @@ -1041,6 +1043,9 @@ pub fn initialize_account<S: std::hash::BuildHasher>(
return Err(InstructionError::AccountAlreadyInitialized);
}

// Authorized signer must sign. (Cluster authority)
verify_authorized_signer(cluster_authority_signer, signers)?;

// node must agree to accept this vote account
verify_authorized_signer(&vote_init.node_pubkey, signers)?;

Expand Down
Loading

0 comments on commit 1e02135

Please sign in to comment.