Skip to content

Commit

Permalink
vote_processor: Add tests for CompactVoteStateUpdate (solana-labs#32229)
Browse files Browse the repository at this point in the history
  • Loading branch information
AshwinSekar authored Jun 21, 2023
1 parent ba05cbf commit c142ba1
Showing 1 changed file with 161 additions and 102 deletions.
263 changes: 161 additions & 102 deletions programs/vote/src/vote_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,8 @@ mod tests {
crate::{
vote_error::VoteError,
vote_instruction::{
authorize, authorize_checked, create_account_with_config, update_commission,
authorize, authorize_checked, compact_update_vote_state,
compact_update_vote_state_switch, create_account_with_config, update_commission,
update_validator_identity, update_vote_state, update_vote_state_switch, vote,
vote_switch, withdraw, CreateVoteAccountConfig, VoteInstruction,
},
Expand Down Expand Up @@ -520,6 +521,28 @@ mod tests {
(vote_pubkey, vote_account_with_epoch_credits)
}

/// Returns Vec of serialized VoteInstruction and flag indicating if it is a vote state update
/// variant, along with the original vote
fn create_serialized_votes() -> (Vote, Vec<(Vec<u8>, bool)>) {
let vote = Vote::new(vec![1], Hash::default());
let vote_state_update = VoteStateUpdate::from(vec![(1, 1)]);
(
vote.clone(),
vec![
(serialize(&VoteInstruction::Vote(vote)).unwrap(), false),
(
serialize(&VoteInstruction::UpdateVoteState(vote_state_update.clone()))
.unwrap(),
true,
),
(
serialize(&VoteInstruction::CompactUpdateVoteState(vote_state_update)).unwrap(),
true,
),
],
)
}

#[test]
fn test_vote_process_instruction_decode_bail() {
process_instruction(
Expand Down Expand Up @@ -765,15 +788,9 @@ mod tests {
#[test]
fn test_vote_signature() {
let (vote_pubkey, vote_account) = create_test_account();
let vote = Vote::new(vec![1], Hash::default());
let (vote, instruction_datas) = create_serialized_votes();
let slot_hashes = SlotHashes::new(&[(*vote.slots.last().unwrap(), vote.hash)]);
let slot_hashes_account = account::create_account_shared_data_for_test(&slot_hashes);
let instruction_data = serialize(&VoteInstruction::Vote(vote.clone())).unwrap();
let mut transaction_accounts = vec![
(vote_pubkey, vote_account),
(sysvar::slot_hashes::id(), slot_hashes_account.clone()),
(sysvar::clock::id(), create_default_clock_account()),
];
let mut instruction_accounts = vec![
AccountMeta {
pubkey: vote_pubkey,
Expand All @@ -792,83 +809,96 @@ mod tests {
},
];

// should fail, unsigned
instruction_accounts[0].is_signer = false;
process_instruction(
&instruction_data,
transaction_accounts.clone(),
instruction_accounts.clone(),
Err(InstructionError::MissingRequiredSignature),
);
instruction_accounts[0].is_signer = true;

// should pass
let accounts = process_instruction(
&instruction_data,
transaction_accounts.clone(),
instruction_accounts.clone(),
Ok(()),
);
let vote_state: VoteState = StateMut::<VoteStateVersions>::state(&accounts[0])
.unwrap()
.convert_to_current();
assert_eq!(
vote_state.votes,
vec![vote_state::LandedVote::from(Lockout::new(
*vote.slots.last().unwrap()
))]
);
assert_eq!(vote_state.credits(), 0);

// should fail, wrong hash
transaction_accounts[1] = (
sysvar::slot_hashes::id(),
account::create_account_shared_data_for_test(&SlotHashes::new(&[(
*vote.slots.last().unwrap(),
solana_sdk::hash::hash(&[0u8]),
)])),
);
process_instruction(
&instruction_data,
transaction_accounts.clone(),
instruction_accounts.clone(),
Err(VoteError::SlotHashMismatch.into()),
);

// should fail, wrong slot
transaction_accounts[1] = (
sysvar::slot_hashes::id(),
account::create_account_shared_data_for_test(&SlotHashes::new(&[(0, vote.hash)])),
);
process_instruction(
&instruction_data,
transaction_accounts.clone(),
instruction_accounts.clone(),
Err(VoteError::SlotsMismatch.into()),
);

// should fail, empty slot_hashes
transaction_accounts[1] = (
sysvar::slot_hashes::id(),
account::create_account_shared_data_for_test(&SlotHashes::new(&[])),
);
process_instruction(
&instruction_data,
transaction_accounts.clone(),
instruction_accounts.clone(),
Err(VoteError::VoteTooOld.into()),
);
transaction_accounts[1] = (sysvar::slot_hashes::id(), slot_hashes_account);

// should fail, uninitialized
let vote_account = AccountSharedData::new(100, VoteState::size_of(), &id());
transaction_accounts[0] = (vote_pubkey, vote_account);
process_instruction(
&instruction_data,
transaction_accounts,
instruction_accounts,
Err(InstructionError::UninitializedAccount),
);
for (instruction_data, is_vote_state_update) in instruction_datas {
let mut transaction_accounts = vec![
(vote_pubkey, vote_account.clone()),
(sysvar::slot_hashes::id(), slot_hashes_account.clone()),
(sysvar::clock::id(), create_default_clock_account()),
];

// should fail, unsigned
instruction_accounts[0].is_signer = false;
process_instruction(
&instruction_data,
transaction_accounts.clone(),
instruction_accounts.clone(),
Err(InstructionError::MissingRequiredSignature),
);
instruction_accounts[0].is_signer = true;

// should pass
let accounts = process_instruction(
&instruction_data,
transaction_accounts.clone(),
instruction_accounts.clone(),
Ok(()),
);
let vote_state: VoteState = StateMut::<VoteStateVersions>::state(&accounts[0])
.unwrap()
.convert_to_current();
assert_eq!(
vote_state.votes,
vec![vote_state::LandedVote::from(Lockout::new(
*vote.slots.last().unwrap()
))]
);
assert_eq!(vote_state.credits(), 0);

// should fail, wrong hash
transaction_accounts[1] = (
sysvar::slot_hashes::id(),
account::create_account_shared_data_for_test(&SlotHashes::new(&[(
*vote.slots.last().unwrap(),
solana_sdk::hash::hash(&[0u8]),
)])),
);
process_instruction(
&instruction_data,
transaction_accounts.clone(),
instruction_accounts.clone(),
Err(VoteError::SlotHashMismatch.into()),
);

// should fail, wrong slot
transaction_accounts[1] = (
sysvar::slot_hashes::id(),
account::create_account_shared_data_for_test(&SlotHashes::new(&[(0, vote.hash)])),
);
process_instruction(
&instruction_data,
transaction_accounts.clone(),
instruction_accounts.clone(),
Err(VoteError::SlotsMismatch.into()),
);

// should fail, empty slot_hashes
transaction_accounts[1] = (
sysvar::slot_hashes::id(),
account::create_account_shared_data_for_test(&SlotHashes::new(&[])),
);
process_instruction(
&instruction_data,
transaction_accounts.clone(),
instruction_accounts.clone(),
Err((if is_vote_state_update {
VoteError::SlotsMismatch
} else {
VoteError::VoteTooOld
})
.into()),
);
transaction_accounts[1] = (sysvar::slot_hashes::id(), slot_hashes_account.clone());

// should fail, uninitialized
let vote_account = AccountSharedData::new(100, VoteState::size_of(), &id());
transaction_accounts[0] = (vote_pubkey, vote_account);
process_instruction(
&instruction_data,
transaction_accounts.clone(),
instruction_accounts.clone(),
Err(InstructionError::UninitializedAccount),
);
}
}

#[test]
Expand Down Expand Up @@ -957,10 +987,9 @@ mod tests {
instruction_accounts.pop();

// should fail, not signed by authorized voter
let vote = Vote::new(vec![1], Hash::default());
let (vote, instruction_datas) = create_serialized_votes();
let slot_hashes = SlotHashes::new(&[(*vote.slots.last().unwrap(), vote.hash)]);
let slot_hashes_account = account::create_account_shared_data_for_test(&slot_hashes);
let instruction_data = serialize(&VoteInstruction::Vote(vote)).unwrap();
transaction_accounts.push((sysvar::slot_hashes::id(), slot_hashes_account));
instruction_accounts.insert(
1,
Expand All @@ -970,25 +999,29 @@ mod tests {
is_writable: false,
},
);
process_instruction(
&instruction_data,
transaction_accounts.clone(),
instruction_accounts.clone(),
Err(InstructionError::MissingRequiredSignature),
);

// should pass, signed by authorized voter
instruction_accounts.push(AccountMeta {
let mut authorized_instruction_accounts = instruction_accounts.clone();
authorized_instruction_accounts.push(AccountMeta {
pubkey: authorized_voter_pubkey,
is_signer: true,
is_writable: false,
});
process_instruction(
&instruction_data,
transaction_accounts,
instruction_accounts,
Ok(()),
);

for (instruction_data, _) in instruction_datas {
process_instruction(
&instruction_data,
transaction_accounts.clone(),
instruction_accounts.clone(),
Err(InstructionError::MissingRequiredSignature),
);

// should pass, signed by authorized voter
process_instruction(
&instruction_data,
transaction_accounts.clone(),
authorized_instruction_accounts.clone(),
Ok(()),
);
}
}

#[test]
Expand Down Expand Up @@ -1732,6 +1765,14 @@ mod tests {
),
Err(InstructionError::InvalidAccountOwner),
);
process_instruction_as_one_arg(
&compact_update_vote_state(
&invalid_vote_state_pubkey(),
&Pubkey::default(),
VoteStateUpdate::default(),
),
Err(InstructionError::InvalidAccountOwner),
);
}

#[test]
Expand Down Expand Up @@ -1886,6 +1927,24 @@ mod tests {
),
Err(InstructionError::InvalidAccountData),
);
process_instruction_as_one_arg(
&compact_update_vote_state(
&Pubkey::default(),
&Pubkey::default(),
VoteStateUpdate::default(),
),
Err(InstructionError::InvalidAccountData),
);

process_instruction_as_one_arg(
&compact_update_vote_state_switch(
&Pubkey::default(),
&Pubkey::default(),
VoteStateUpdate::default(),
Hash::default(),
),
Err(InstructionError::InvalidAccountData),
);

process_instruction_as_one_arg(
&update_validator_identity(
Expand Down

0 comments on commit c142ba1

Please sign in to comment.