diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 50ee10d21d..f29058e1e7 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -354,7 +354,7 @@ pub enum CliCommand { // Vote Commands CreateVoteAccount { seed: Option, - node_pubkey: Pubkey, + identity_account: SignerIndex, authorized_voter: Option, authorized_withdrawer: Option, commission: u8, @@ -377,7 +377,7 @@ pub enum CliCommand { }, VoteUpdateValidator { vote_account_pubkey: Pubkey, - new_identity_pubkey: Pubkey, + new_identity_account: SignerIndex, }, // Wallet Commands Address, @@ -1947,7 +1947,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult { // Create vote account CliCommand::CreateVoteAccount { seed, - node_pubkey, + identity_account, authorized_voter, authorized_withdrawer, commission, @@ -1955,7 +1955,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult { &rpc_client, config, seed, - &node_pubkey, + *identity_account, authorized_voter, authorized_withdrawer, *commission, @@ -1997,12 +1997,12 @@ pub fn process_command(config: &CliConfig) -> ProcessResult { ), CliCommand::VoteUpdateValidator { vote_account_pubkey, - new_identity_pubkey, + new_identity_account, } => process_vote_update_validator( &rpc_client, config, &vote_account_pubkey, - &new_identity_pubkey, + *new_identity_account, ), // Wallet Commands @@ -3210,15 +3210,15 @@ mod tests { let bob_keypair = Keypair::new(); let bob_pubkey = bob_keypair.pubkey(); - let node_pubkey = Pubkey::new_rand(); + let identity_keypair = Keypair::new(); config.command = CliCommand::CreateVoteAccount { seed: None, - node_pubkey, + identity_account: 2, authorized_voter: Some(bob_pubkey), authorized_withdrawer: Some(bob_pubkey), commission: 0, }; - config.signers = vec![&keypair, &bob_keypair]; + config.signers = vec![&keypair, &bob_keypair, &identity_keypair]; let signature = process_command(&config); assert_eq!(signature.unwrap(), SIGNATURE.to_string()); @@ -3232,11 +3232,11 @@ mod tests { let signature = process_command(&config); assert_eq!(signature.unwrap(), SIGNATURE.to_string()); - let new_identity_pubkey = Pubkey::new_rand(); - config.signers = vec![&keypair, &bob_keypair]; + let new_identity_keypair = Keypair::new(); + config.signers = vec![&keypair, &bob_keypair, &new_identity_keypair]; config.command = CliCommand::VoteUpdateValidator { vote_account_pubkey: bob_pubkey, - new_identity_pubkey, + new_identity_account: 2, }; let signature = process_command(&config); assert_eq!(signature.unwrap(), SIGNATURE.to_string()); @@ -3454,14 +3454,15 @@ mod tests { assert!(process_command(&config).is_err()); let bob_keypair = Keypair::new(); + let identity_keypair = Keypair::new(); config.command = CliCommand::CreateVoteAccount { seed: None, - node_pubkey, + identity_account: 2, authorized_voter: Some(bob_pubkey), authorized_withdrawer: Some(bob_pubkey), commission: 0, }; - config.signers = vec![&keypair, &bob_keypair]; + config.signers = vec![&keypair, &bob_keypair, &identity_keypair]; assert!(process_command(&config).is_err()); config.command = CliCommand::VoteAuthorize { @@ -3473,7 +3474,7 @@ mod tests { config.command = CliCommand::VoteUpdateValidator { vote_account_pubkey: bob_pubkey, - new_identity_pubkey: bob_pubkey, + new_identity_account: 1, }; assert!(process_command(&config).is_err()); diff --git a/cli/src/vote.rs b/cli/src/vote.rs index 86f8ac7926..4716f19129 100644 --- a/cli/src/vote.rs +++ b/cli/src/vote.rs @@ -40,13 +40,13 @@ impl VoteSubCommands for App<'_, '_> { .help("Vote account keypair to fund"), ) .arg( - Arg::with_name("identity_pubkey") + Arg::with_name("identity_account") .index(2) - .value_name("PUBKEY") + .value_name("KEYPAIR") .takes_value(true) .required(true) - .validator(is_valid_pubkey) - .help("Validator that will vote with this account"), + .validator(is_valid_signer) + .help("Keypair of validator that will vote with this account"), ) .arg( Arg::with_name("commission") @@ -137,22 +137,22 @@ impl VoteSubCommands for App<'_, '_> { .help("Vote account to update"), ) .arg( - Arg::with_name("new_identity_pubkey") + Arg::with_name("new_identity_account") .index(2) - .value_name("PUBKEY") + .value_name("KEYPAIR") .takes_value(true) .required(true) - .validator(is_valid_pubkey) - .help("New validator that will vote with this account"), + .validator(is_valid_signer) + .help("Keypair of new validator that will vote with this account"), ) .arg( - Arg::with_name("authorized_voter") + Arg::with_name("authorized_withdrawer") .index(3) .value_name("KEYPAIR") .takes_value(true) .required(true) .validator(is_valid_signer) - .help("Authorized voter keypair"), + .help("Authorized withdrawer keypair"), ) ) .subcommand( @@ -232,14 +232,15 @@ pub fn parse_create_vote_account( ) -> Result { let (vote_account, _) = signer_of(matches, "vote_account", wallet_manager)?; let seed = matches.value_of("seed").map(|s| s.to_string()); - let identity_pubkey = pubkey_of_signer(matches, "identity_pubkey", wallet_manager)?.unwrap(); + let (identity_account, identity_pubkey) = + signer_of(matches, "identity_account", 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 = pubkey_of_signer(matches, "authorized_withdrawer", wallet_manager)?; let payer_provided = None; - let CliSignerInfo { signers } = generate_unique_signers( - vec![payer_provided, vote_account], + let signer_info = generate_unique_signers( + vec![payer_provided, vote_account, identity_account], matches, default_signer_path, wallet_manager, @@ -248,12 +249,12 @@ pub fn parse_create_vote_account( Ok(CliCommandInfo { command: CliCommand::CreateVoteAccount { seed, - node_pubkey: identity_pubkey, + identity_account: signer_info.index_of(identity_pubkey).unwrap(), authorized_voter, authorized_withdrawer, commission, }, - signers, + signers: signer_info.signers, }) } @@ -293,13 +294,13 @@ pub fn parse_vote_update_validator( ) -> Result { let vote_account_pubkey = pubkey_of_signer(matches, "vote_account_pubkey", wallet_manager)?.unwrap(); - let new_identity_pubkey = - pubkey_of_signer(matches, "new_identity_pubkey", wallet_manager)?.unwrap(); - let (authorized_voter, _) = signer_of(matches, "authorized_voter", wallet_manager)?; + let (new_identity_account, new_identity_pubkey) = + signer_of(matches, "new_identity_account", wallet_manager)?; + let (authorized_withdrawer, _) = signer_of(matches, "authorized_withdrawer", wallet_manager)?; let payer_provided = None; - let CliSignerInfo { signers } = generate_unique_signers( - vec![payer_provided, authorized_voter], + let signer_info = generate_unique_signers( + vec![payer_provided, authorized_withdrawer, new_identity_account], matches, default_signer_path, wallet_manager, @@ -308,9 +309,9 @@ pub fn parse_vote_update_validator( Ok(CliCommandInfo { command: CliCommand::VoteUpdateValidator { vote_account_pubkey, - new_identity_pubkey, + new_identity_account: signer_info.index_of(new_identity_pubkey).unwrap(), }, - signers, + signers: signer_info.signers, }) } @@ -372,7 +373,7 @@ pub fn process_create_vote_account( rpc_client: &RpcClient, config: &CliConfig, seed: &Option, - identity_pubkey: &Pubkey, + identity_account: SignerIndex, authorized_voter: &Option, authorized_withdrawer: &Option, commission: u8, @@ -389,6 +390,8 @@ pub fn process_create_vote_account( (&vote_account_address, "vote_account".to_string()), )?; + let identity_account = config.signers[identity_account]; + let identity_pubkey = identity_account.pubkey(); check_unique_pubkeys( (&vote_account_address, "vote_account".to_string()), (&identity_pubkey, "identity_pubkey".to_string()), @@ -411,9 +414,9 @@ pub fn process_create_vote_account( .max(1); let vote_init = VoteInit { - node_pubkey: *identity_pubkey, - authorized_voter: authorized_voter.unwrap_or(*identity_pubkey), - authorized_withdrawer: authorized_withdrawer.unwrap_or(*identity_pubkey), + node_pubkey: identity_pubkey, + authorized_voter: authorized_voter.unwrap_or(identity_pubkey), + authorized_withdrawer: authorized_withdrawer.unwrap_or(identity_pubkey), commission, }; @@ -486,18 +489,20 @@ pub fn process_vote_update_validator( rpc_client: &RpcClient, config: &CliConfig, vote_account_pubkey: &Pubkey, - new_identity_pubkey: &Pubkey, + new_identity_account: SignerIndex, ) -> ProcessResult { - let authorized_voter = config.signers[1]; + let authorized_withdrawer = config.signers[1]; + let new_identity_account = config.signers[new_identity_account]; + let new_identity_pubkey = new_identity_account.pubkey(); check_unique_pubkeys( (vote_account_pubkey, "vote_account_pubkey".to_string()), - (new_identity_pubkey, "new_identity_pubkey".to_string()), + (&new_identity_pubkey, "new_identity_account".to_string()), )?; let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?; let ixs = vec![vote_instruction::update_node( vote_account_pubkey, - &authorized_voter.pubkey(), - new_identity_pubkey, + &authorized_withdrawer.pubkey(), + &new_identity_pubkey, )]; let message = Message::new_with_payer(&ixs, Some(&config.signers[0].pubkey())); @@ -675,13 +680,14 @@ mod tests { let keypair = Keypair::new(); write_keypair(&keypair, tmp_file.as_file_mut()).unwrap(); // Test CreateVoteAccount SubCommand - let node_pubkey = Pubkey::new_rand(); - let node_pubkey_string = format!("{}", node_pubkey); + let (identity_keypair_file, mut tmp_file) = make_tmp_file(); + let identity_keypair = Keypair::new(); + write_keypair(&identity_keypair, tmp_file.as_file_mut()).unwrap(); let test_create_vote_account = test_commands.clone().get_matches_from(vec![ "test", "create-vote-account", &keypair_file, - &node_pubkey_string, + &identity_keypair_file, "--commission", "10", ]); @@ -690,14 +696,15 @@ mod tests { CliCommandInfo { command: CliCommand::CreateVoteAccount { seed: None, - node_pubkey, + identity_account: 2, authorized_voter: None, authorized_withdrawer: None, commission: 10, }, signers: vec![ read_keypair_file(&default_keypair_file).unwrap().into(), - Box::new(keypair) + Box::new(keypair), + read_keypair_file(&identity_keypair_file).unwrap().into(), ], } ); @@ -710,21 +717,22 @@ mod tests { "test", "create-vote-account", &keypair_file, - &node_pubkey_string, + &identity_keypair_file, ]); assert_eq!( parse_command(&test_create_vote_account2, &default_keypair_file, None).unwrap(), CliCommandInfo { command: CliCommand::CreateVoteAccount { seed: None, - node_pubkey, + identity_account: 2, authorized_voter: None, authorized_withdrawer: None, commission: 100, }, signers: vec![ read_keypair_file(&default_keypair_file).unwrap().into(), - Box::new(keypair) + Box::new(keypair), + read_keypair_file(&identity_keypair_file).unwrap().into(), ], } ); @@ -739,7 +747,7 @@ mod tests { "test", "create-vote-account", &keypair_file, - &node_pubkey_string, + &identity_keypair_file, "--authorized-voter", &authed.to_string(), ]); @@ -748,14 +756,15 @@ mod tests { CliCommandInfo { command: CliCommand::CreateVoteAccount { seed: None, - node_pubkey, + identity_account: 2, authorized_voter: Some(authed), authorized_withdrawer: None, commission: 100 }, signers: vec![ read_keypair_file(&default_keypair_file).unwrap().into(), - Box::new(keypair) + Box::new(keypair), + read_keypair_file(&identity_keypair_file).unwrap().into(), ], } ); @@ -768,7 +777,7 @@ mod tests { "test", "create-vote-account", &keypair_file, - &node_pubkey_string, + &identity_keypair_file, "--authorized-withdrawer", &authed.to_string(), ]); @@ -777,14 +786,15 @@ mod tests { CliCommandInfo { command: CliCommand::CreateVoteAccount { seed: None, - node_pubkey, + identity_account: 2, authorized_voter: None, authorized_withdrawer: Some(authed), commission: 100 }, signers: vec![ read_keypair_file(&default_keypair_file).unwrap().into(), - Box::new(keypair) + Box::new(keypair), + read_keypair_file(&identity_keypair_file).unwrap().into(), ], } ); @@ -793,7 +803,7 @@ mod tests { "test", "vote-update-validator", &pubkey_string, - &pubkey2_string, + &identity_keypair_file, &keypair_file, ]); assert_eq!( @@ -801,11 +811,12 @@ mod tests { CliCommandInfo { command: CliCommand::VoteUpdateValidator { vote_account_pubkey: pubkey, - new_identity_pubkey: pubkey2, + new_identity_account: 2, }, signers: vec![ read_keypair_file(&default_keypair_file).unwrap().into(), - Box::new(read_keypair_file(&keypair_file).unwrap()) + Box::new(read_keypair_file(&keypair_file).unwrap()), + read_keypair_file(&identity_keypair_file).unwrap().into(), ], } ); diff --git a/cli/tests/stake.rs b/cli/tests/stake.rs index edc85311d9..6065c02109 100644 --- a/cli/tests/stake.rs +++ b/cli/tests/stake.rs @@ -68,7 +68,7 @@ fn test_stake_delegation_force() { config.signers = vec![&default_signer, &vote_keypair]; config.command = CliCommand::CreateVoteAccount { seed: None, - node_pubkey: config.signers[0].pubkey(), + identity_account: 0, authorized_voter: None, authorized_withdrawer: None, commission: 0, diff --git a/cli/tests/vote.rs b/cli/tests/vote.rs index cbe27c70d3..42f87b35f3 100644 --- a/cli/tests/vote.rs +++ b/cli/tests/vote.rs @@ -57,7 +57,7 @@ fn test_vote_authorize_and_withdraw() { config.signers = vec![&default_signer, &vote_account_keypair]; config.command = CliCommand::CreateVoteAccount { seed: None, - node_pubkey: config.signers[0].pubkey(), + identity_account: 0, authorized_voter: None, authorized_withdrawer: Some(config.signers[0].pubkey()), commission: 0, @@ -104,6 +104,15 @@ fn test_vote_authorize_and_withdraw() { check_balance(expected_balance - 100, &rpc_client, &vote_account_pubkey); check_balance(100, &rpc_client, &destination_account); + // Re-assign validator identity + let new_identity_keypair = Keypair::new(); + config.signers.push(&new_identity_keypair); + config.command = CliCommand::VoteUpdateValidator { + vote_account_pubkey, + new_identity_account: 2, + }; + process_command(&config).unwrap(); + server.close().unwrap(); remove_dir_all(ledger_path).unwrap(); } diff --git a/ledger/src/leader_schedule_cache.rs b/ledger/src/leader_schedule_cache.rs index 82fac7f18f..6b7f5ba6f3 100644 --- a/ledger/src/leader_schedule_cache.rs +++ b/ledger/src/leader_schedule_cache.rs @@ -272,7 +272,7 @@ mod tests { EpochSchedule, DEFAULT_LEADER_SCHEDULE_SLOT_OFFSET, DEFAULT_SLOTS_PER_EPOCH, MINIMUM_SLOTS_PER_EPOCH, }; - use solana_sdk::signature::Keypair; + use solana_sdk::signature::{Keypair, Signer}; use std::{sync::mpsc::channel, sync::Arc, thread::Builder}; #[test] @@ -526,15 +526,16 @@ mod tests { let cache = Arc::new(LeaderScheduleCache::new_from_bank(&bank)); // Create new vote account - let node_pubkey = Pubkey::new_rand(); + let validator_identity = Keypair::new(); let vote_account = Keypair::new(); setup_vote_and_stake_accounts( &bank, &mint_keypair, &vote_account, - &node_pubkey, + &validator_identity, BOOTSTRAP_VALIDATOR_LAMPORTS, ); + let node_pubkey = validator_identity.pubkey(); // Have to wait until the epoch at after the epoch stakes generated at genesis // for the new votes to take effect. diff --git a/ledger/src/staking_utils.rs b/ledger/src/staking_utils.rs index c55e5d1b35..7aafae66af 100644 --- a/ledger/src/staking_utils.rs +++ b/ledger/src/staking_utils.rs @@ -130,7 +130,7 @@ pub(crate) mod tests { bank: &Bank, from_account: &Keypair, vote_account: &Keypair, - node_pubkey: &Pubkey, + validator_identity_account: &Keypair, amount: u64, ) { let vote_pubkey = vote_account.pubkey(); @@ -146,12 +146,12 @@ pub(crate) mod tests { process_instructions( bank, - &[from_account, vote_account], + &[from_account, vote_account, validator_identity_account], vote_instruction::create_account( &from_account.pubkey(), &vote_pubkey, &VoteInit { - node_pubkey: *node_pubkey, + node_pubkey: validator_identity_account.pubkey(), authorized_voter: vote_pubkey, authorized_withdrawer: vote_pubkey, commission: 0, @@ -209,13 +209,7 @@ pub(crate) mod tests { // Make a mint vote account. Because the mint has nonzero stake, this // should show up in the active set - setup_vote_and_stake_accounts( - &bank, - &mint_keypair, - &vote_account, - &mint_keypair.pubkey(), - stake, - ); + setup_vote_and_stake_accounts(&bank, &mint_keypair, &vote_account, &mint_keypair, stake); // simulated stake let other_stake = Stake { diff --git a/programs/vote/src/vote_instruction.rs b/programs/vote/src/vote_instruction.rs index cc1475bdae..22c10682ea 100644 --- a/programs/vote/src/vote_instruction.rs +++ b/programs/vote/src/vote_instruction.rs @@ -51,6 +51,7 @@ impl DecodeError for VoteError { #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] pub enum VoteInstruction { /// Initialize the VoteState for this `vote account` + /// requires VoteInit::node_pubkey signature /// /// Expects 3 Accounts: /// 0 - Uninitialized Vote account @@ -87,13 +88,13 @@ pub enum VoteInstruction { Withdraw(u64), /// Update the vote account's validator identity (node id) - /// requires authorized voter signature + /// requires authorized withdrawer and new validator identity signature /// /// Expects 2 Accounts: /// 0 - Vote account to be updated with the Pubkey for authorization - /// 1 - Clock sysvar Account that carries clock bank epoch + /// 1 - New validator identity (node id) /// - UpdateNode(Pubkey), + UpdateNode, } fn initialize_account(vote_pubkey: &Pubkey, vote_init: &VoteInit) -> Instruction { @@ -101,7 +102,9 @@ fn initialize_account(vote_pubkey: &Pubkey, vote_init: &VoteInit) -> Instruction AccountMeta::new(*vote_pubkey, false), AccountMeta::new_readonly(sysvar::rent::id(), false), AccountMeta::new_readonly(sysvar::clock::id(), false), - ]; + ] + .with_signer(&vote_init.node_pubkey); + Instruction::new( id(), &VoteInstruction::InitializeAccount(*vote_init), @@ -165,20 +168,16 @@ pub fn authorize( pub fn update_node( vote_pubkey: &Pubkey, - authorized_voter_pubkey: &Pubkey, + authorized_withdrawer_pubkey: &Pubkey, node_pubkey: &Pubkey, ) -> Instruction { let account_metas = vec![ AccountMeta::new(*vote_pubkey, false), - AccountMeta::new_readonly(sysvar::clock::id(), false), + AccountMeta::new_readonly(*node_pubkey, true), ] - .with_signer(authorized_voter_pubkey); + .with_signer(authorized_withdrawer_pubkey); - Instruction::new( - id(), - &VoteInstruction::UpdateNode(*node_pubkey), - account_metas, - ) + Instruction::new(id(), &VoteInstruction::UpdateNode, account_metas) } pub fn vote(vote_pubkey: &Pubkey, authorized_voter_pubkey: &Pubkey, vote: Vote) -> Instruction { @@ -194,7 +193,7 @@ pub fn vote(vote_pubkey: &Pubkey, authorized_voter_pubkey: &Pubkey, vote: Vote) pub fn withdraw( vote_pubkey: &Pubkey, - withdrawer_pubkey: &Pubkey, + authorized_withdrawer_pubkey: &Pubkey, lamports: u64, to_pubkey: &Pubkey, ) -> Instruction { @@ -202,7 +201,7 @@ pub fn withdraw( AccountMeta::new(*vote_pubkey, false), AccountMeta::new(*to_pubkey, false), ] - .with_signer(withdrawer_pubkey); + .with_signer(authorized_withdrawer_pubkey); Instruction::new(id(), &VoteInstruction::Withdraw(lamports), account_metas) } @@ -228,6 +227,7 @@ pub fn process_instruction( vote_state::initialize_account( me, &vote_init, + &signers, &Clock::from_keyed_account(next_keyed_account(keyed_accounts)?)?, ) } @@ -238,11 +238,10 @@ pub fn process_instruction( &signers, &Clock::from_keyed_account(next_keyed_account(keyed_accounts)?)?, ), - VoteInstruction::UpdateNode(node_pubkey) => vote_state::update_node( + VoteInstruction::UpdateNode => vote_state::update_node( me, - &node_pubkey, + next_keyed_account(keyed_accounts)?.unsigned_key(), &signers, - &Clock::from_keyed_account(next_keyed_account(keyed_accounts)?)?, ), VoteInstruction::Vote(vote) => { inc_new_counter_info!("vote-native", 1); diff --git a/programs/vote/src/vote_state/mod.rs b/programs/vote/src/vote_state/mod.rs index aabda72376..925d433995 100644 --- a/programs/vote/src/vote_state/mod.rs +++ b/programs/vote/src/vote_state/mod.rs @@ -582,16 +582,15 @@ pub fn update_node( vote_account: &KeyedAccount, node_pubkey: &Pubkey, signers: &HashSet, - clock: &Clock, ) -> Result<(), InstructionError> { let mut vote_state: VoteState = State::::state(vote_account)?.convert_to_current(); - let authorized_voter = vote_state - .get_and_update_authorized_voter(clock.epoch) - .expect("the clock epoch is monotonically increasing, so authorized voter must be known"); - // current authorized voter must say "yay" - verify_authorized_signer(&authorized_voter, signers)?; + // current authorized withdrawer must say "yay" + verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?; + + // new node must say "yay" + verify_authorized_signer(&node_pubkey, signers)?; vote_state.node_pubkey = *node_pubkey; @@ -632,9 +631,10 @@ pub fn withdraw( /// Initialize the vote_state for a vote account /// Assumes that the account is being init as part of a account creation or balance transfer and /// that the transaction must be signed by the staker's keys -pub fn initialize_account( +pub fn initialize_account( vote_account: &KeyedAccount, vote_init: &VoteInit, + signers: &HashSet, clock: &Clock, ) -> Result<(), InstructionError> { let versioned = State::::state(vote_account)?; @@ -643,6 +643,9 @@ pub fn initialize_account( return Err(InstructionError::AccountAlreadyInitialized); } + // node must agree to accept this vote account + verify_authorized_signer(&vote_init.node_pubkey, signers)?; + vote_account.set_state(&VoteStateVersions::Current(Box::new(VoteState::new( vote_init, clock, )))) @@ -664,7 +667,7 @@ pub fn process_vote( let mut vote_state = versioned.convert_to_current(); let authorized_voter = vote_state .get_and_update_authorized_voter(clock.epoch) - .expect("the clock epoch is monotonically increasinig, so authorized voter must be known"); + .expect("the clock epoch is monotonically increasing, so authorized voter must be known"); verify_authorized_signer(&authorized_voter, signers)?; vote_state.process_vote(vote, slot_hashes, clock.epoch)?; @@ -745,11 +748,14 @@ mod tests { fn test_initialize_vote_account() { let vote_account_pubkey = Pubkey::new_rand(); let vote_account = Account::new_ref(100, VoteState::size_of(), &id()); + let vote_account = KeyedAccount::new(&vote_account_pubkey, false, &vote_account); let node_pubkey = Pubkey::new_rand(); + let node_account = RefCell::new(Account::default()); + let keyed_accounts = &[]; + let signers: HashSet = get_signers(keyed_accounts); - //init should pass - let vote_account = KeyedAccount::new(&vote_account_pubkey, false, &vote_account); + //init should fail, node_pubkey didn't sign the transaction let res = initialize_account( &vote_account, &VoteInit { @@ -758,6 +764,24 @@ mod tests { authorized_withdrawer: vote_account_pubkey, commission: 0, }, + &signers, + &Clock::default(), + ); + assert_eq!(res, Err(InstructionError::MissingRequiredSignature)); + + let keyed_accounts = &[KeyedAccount::new(&node_pubkey, true, &node_account)]; + let signers: HashSet = get_signers(keyed_accounts); + + //init should pass + let res = initialize_account( + &vote_account, + &VoteInit { + node_pubkey, + authorized_voter: vote_account_pubkey, + authorized_withdrawer: vote_account_pubkey, + commission: 0, + }, + &signers, &Clock::default(), ); assert_eq!(res, Ok(())); @@ -771,6 +795,7 @@ mod tests { authorized_withdrawer: vote_account_pubkey, commission: 0, }, + &signers, &Clock::default(), ); assert_eq!(res, Err(InstructionError::AccountAlreadyInitialized)); @@ -789,6 +814,25 @@ mod tests { ) } + fn create_test_account_with_authorized() -> (Pubkey, Pubkey, Pubkey, RefCell) { + let vote_pubkey = Pubkey::new_rand(); + let authorized_voter = Pubkey::new_rand(); + let authorized_withdrawer = Pubkey::new_rand(); + + ( + vote_pubkey, + authorized_voter, + authorized_withdrawer, + RefCell::new(vote_state::create_account_with_authorized( + &Pubkey::new_rand(), + &authorized_voter, + &authorized_withdrawer, + 0, + 100, + )), + ) + } + fn simulate_process_vote( vote_pubkey: &Pubkey, vote_account: &RefCell, @@ -906,43 +950,46 @@ mod tests { #[test] fn test_vote_update_node_id() { - let (vote_pubkey, vote_account) = create_test_account(); + let (vote_pubkey, _authorized_voter, authorized_withdrawer, vote_account) = + create_test_account_with_authorized(); let node_pubkey = Pubkey::new_rand(); + let node_account = RefCell::new(Account::default()); + let authorized_withdrawer_account = RefCell::new(Account::default()); - let keyed_accounts = &[KeyedAccount::new(&vote_pubkey, false, &vote_account)]; + let keyed_accounts = &[ + KeyedAccount::new(&vote_pubkey, true, &vote_account), + KeyedAccount::new(&node_pubkey, false, &node_account), + KeyedAccount::new(&authorized_withdrawer, true, &authorized_withdrawer_account), + ]; let signers: HashSet = get_signers(keyed_accounts); - let res = update_node( - &keyed_accounts[0], - &node_pubkey, - &signers, - &Clock::default(), - ); + let res = update_node(&keyed_accounts[0], &node_pubkey, &signers); + assert_eq!(res, Err(InstructionError::MissingRequiredSignature)); + + let keyed_accounts = &[ + KeyedAccount::new(&vote_pubkey, true, &vote_account), + KeyedAccount::new(&node_pubkey, true, &node_account), + KeyedAccount::new( + &authorized_withdrawer, + false, + &authorized_withdrawer_account, + ), + ]; + let signers: HashSet = get_signers(keyed_accounts); + let res = update_node(&keyed_accounts[0], &node_pubkey, &signers); assert_eq!(res, Err(InstructionError::MissingRequiredSignature)); let vote_state: VoteState = StateMut::::state(&*vote_account.borrow()) .unwrap() .convert_to_current(); assert!(vote_state.node_pubkey != node_pubkey); - let keyed_accounts = &[KeyedAccount::new(&vote_pubkey, true, &vote_account)]; + let keyed_accounts = &[ + KeyedAccount::new(&vote_pubkey, true, &vote_account), + KeyedAccount::new(&node_pubkey, true, &node_account), + KeyedAccount::new(&authorized_withdrawer, true, &authorized_withdrawer_account), + ]; let signers: HashSet = get_signers(keyed_accounts); - let res = update_node( - &keyed_accounts[0], - &node_pubkey, - &signers, - &Clock::default(), - ); - assert_eq!(res, Ok(())); - let vote_state: VoteState = StateMut::::state(&*vote_account.borrow()) - .unwrap() - .convert_to_current(); - assert_eq!(vote_state.node_pubkey, node_pubkey); - - let keyed_accounts = &[KeyedAccount::new(&vote_pubkey, true, &vote_account)]; - let signers: HashSet = get_signers(keyed_accounts); - let mut clock = Clock::default(); - clock.epoch += 10; - let res = update_node(&keyed_accounts[0], &node_pubkey, &signers, &clock); + let res = update_node(&keyed_accounts[0], &node_pubkey, &signers); assert_eq!(res, Ok(())); let vote_state: VoteState = StateMut::::state(&*vote_account.borrow()) .unwrap() diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 3b50bb439d..00f8487c94 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -4905,15 +4905,19 @@ mod tests { assert!(bank.get_account(&solana_vote_program::id()).is_some()); let mock_account = Keypair::new(); + let mock_validator_identity = Keypair::new(); let instructions = vote_instruction::create_account( &mint_keypair.pubkey(), &mock_account.pubkey(), - &VoteInit::default(), + &VoteInit { + node_pubkey: mock_validator_identity.pubkey(), + ..VoteInit::default() + }, 1, ); let transaction = Transaction::new_signed_instructions( - &[&mint_keypair, &mock_account], + &[&mint_keypair, &mock_account, &mock_validator_identity], instructions, bank.last_blockhash(), ); @@ -4946,15 +4950,19 @@ mod tests { } let mock_account = Keypair::new(); + let mock_validator_identity = Keypair::new(); let instructions = vote_instruction::create_account( &mint_keypair.pubkey(), &mock_account.pubkey(), - &VoteInit::default(), + &VoteInit { + node_pubkey: mock_validator_identity.pubkey(), + ..VoteInit::default() + }, 1, ); let transaction = Transaction::new_signed_instructions( - &[&mint_keypair, &mock_account], + &[&mint_keypair, &mock_account, &mock_validator_identity], instructions, bank.last_blockhash(), ); diff --git a/runtime/tests/stake.rs b/runtime/tests/stake.rs index ea9cad145e..a4b1b88df3 100644 --- a/runtime/tests/stake.rs +++ b/runtime/tests/stake.rs @@ -163,7 +163,8 @@ fn test_stake_account_lifetime() { let stake_pubkey = stake_keypair.pubkey(); let vote_keypair = Keypair::new(); let vote_pubkey = vote_keypair.pubkey(); - let node_pubkey = Pubkey::new_rand(); + let identity_keypair = Keypair::new(); + let identity_pubkey = identity_keypair.pubkey(); let GenesisConfigInfo { mut genesis_config, @@ -183,7 +184,7 @@ fn test_stake_account_lifetime() { &mint_pubkey, &vote_pubkey, &VoteInit { - node_pubkey, + node_pubkey: identity_pubkey, authorized_voter: vote_pubkey, authorized_withdrawer: vote_pubkey, commission: 50, @@ -191,7 +192,7 @@ fn test_stake_account_lifetime() { 10, )); bank_client - .send_message(&[&mint_keypair, &vote_keypair], message) + .send_message(&[&mint_keypair, &vote_keypair, &identity_keypair], message) .expect("failed to create vote account"); let authorized = stake_state::Authorized::auto(&stake_pubkey); @@ -394,7 +395,8 @@ fn test_stake_account_lifetime() { fn test_create_stake_account_from_seed() { let vote_keypair = Keypair::new(); let vote_pubkey = vote_keypair.pubkey(); - let node_pubkey = Pubkey::new_rand(); + let identity_keypair = Keypair::new(); + let identity_pubkey = identity_keypair.pubkey(); let GenesisConfigInfo { mut genesis_config, @@ -418,7 +420,7 @@ fn test_create_stake_account_from_seed() { &mint_pubkey, &vote_pubkey, &VoteInit { - node_pubkey, + node_pubkey: identity_pubkey, authorized_voter: vote_pubkey, authorized_withdrawer: vote_pubkey, commission: 50, @@ -426,7 +428,7 @@ fn test_create_stake_account_from_seed() { 10, )); bank_client - .send_message(&[&mint_keypair, &vote_keypair], message) + .send_message(&[&mint_keypair, &vote_keypair, &identity_keypair], message) .expect("failed to create vote account"); let authorized = stake_state::Authorized::auto(&mint_pubkey);