Compact vote state updates to reduce block size (#26616)
* Compact vote state updates to reduce block size * Add rpc transaction tests
This commit is contained in:
parent
1a5b830294
commit
8d69e8d447
|
@ -87,11 +87,22 @@ impl SwitchForkDecision {
|
||||||
v,
|
v,
|
||||||
*switch_proof_hash,
|
*switch_proof_hash,
|
||||||
)),
|
)),
|
||||||
(SwitchForkDecision::SameFork, VoteTransaction::CompactVoteStateUpdate(_v)) => None,
|
(SwitchForkDecision::SameFork, VoteTransaction::CompactVoteStateUpdate(v)) => {
|
||||||
|
Some(vote_instruction::compact_update_vote_state(
|
||||||
|
vote_account_pubkey,
|
||||||
|
authorized_voter_pubkey,
|
||||||
|
v,
|
||||||
|
))
|
||||||
|
}
|
||||||
(
|
(
|
||||||
SwitchForkDecision::SwitchProof(_switch_proof_hash),
|
SwitchForkDecision::SwitchProof(switch_proof_hash),
|
||||||
VoteTransaction::CompactVoteStateUpdate(_v),
|
VoteTransaction::CompactVoteStateUpdate(v),
|
||||||
) => None,
|
) => Some(vote_instruction::compact_update_vote_state_switch(
|
||||||
|
vote_account_pubkey,
|
||||||
|
authorized_voter_pubkey,
|
||||||
|
v,
|
||||||
|
*switch_proof_hash,
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ use {
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
clock::{BankId, Slot, MAX_PROCESSING_AGE, NUM_CONSECUTIVE_LEADER_SLOTS},
|
clock::{BankId, Slot, MAX_PROCESSING_AGE, NUM_CONSECUTIVE_LEADER_SLOTS},
|
||||||
|
feature_set,
|
||||||
genesis_config::ClusterType,
|
genesis_config::ClusterType,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
|
@ -64,7 +65,7 @@ use {
|
||||||
timing::timestamp,
|
timing::timestamp,
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
},
|
},
|
||||||
solana_vote_program::vote_state::VoteTransaction,
|
solana_vote_program::vote_state::{CompactVoteStateUpdate, VoteTransaction},
|
||||||
std::{
|
std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
result,
|
result,
|
||||||
|
@ -1980,6 +1981,16 @@ impl ReplayStage {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Send our last few votes along with the new one
|
// Send our last few votes along with the new one
|
||||||
|
// Compact the vote state update before sending
|
||||||
|
let should_compact = bank
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::compact_vote_state_updates::id());
|
||||||
|
let vote = match (should_compact, vote) {
|
||||||
|
(true, VoteTransaction::VoteStateUpdate(vote_state_update)) => {
|
||||||
|
VoteTransaction::from(CompactVoteStateUpdate::from(vote_state_update))
|
||||||
|
}
|
||||||
|
(_, vote) => vote,
|
||||||
|
};
|
||||||
let vote_ix = switch_fork_decision
|
let vote_ix = switch_fork_decision
|
||||||
.to_vote_instruction(
|
.to_vote_instruction(
|
||||||
vote,
|
vote,
|
||||||
|
|
|
@ -4,8 +4,8 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
id,
|
id,
|
||||||
vote_state::{
|
vote_state::{
|
||||||
Vote, VoteAuthorize, VoteAuthorizeCheckedWithSeedArgs, VoteAuthorizeWithSeedArgs,
|
CompactVoteStateUpdate, Vote, VoteAuthorize, VoteAuthorizeCheckedWithSeedArgs,
|
||||||
VoteInit, VoteState, VoteStateUpdate,
|
VoteAuthorizeWithSeedArgs, VoteInit, VoteState, VoteStateUpdate,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
serde_derive::{Deserialize, Serialize},
|
serde_derive::{Deserialize, Serialize},
|
||||||
|
@ -103,6 +103,20 @@ pub enum VoteInstruction {
|
||||||
/// 1. `[SIGNER]` Vote authority
|
/// 1. `[SIGNER]` Vote authority
|
||||||
UpdateVoteStateSwitch(VoteStateUpdate, Hash),
|
UpdateVoteStateSwitch(VoteStateUpdate, Hash),
|
||||||
|
|
||||||
|
/// Update the onchain vote state for the signer.
|
||||||
|
///
|
||||||
|
/// # Account references
|
||||||
|
/// 0. `[Write]` Vote account to vote with
|
||||||
|
/// 1. `[SIGNER]` Vote authority
|
||||||
|
CompactUpdateVoteState(CompactVoteStateUpdate),
|
||||||
|
|
||||||
|
/// Update the onchain vote state for the signer along with a switching proof.
|
||||||
|
///
|
||||||
|
/// # Account references
|
||||||
|
/// 0. `[Write]` Vote account to vote with
|
||||||
|
/// 1. `[SIGNER]` Vote authority
|
||||||
|
CompactUpdateVoteStateSwitch(CompactVoteStateUpdate, Hash),
|
||||||
|
|
||||||
/// Given that the current Voter or Withdrawer authority is a derived key,
|
/// Given that the current Voter or Withdrawer authority is a derived key,
|
||||||
/// this instruction allows someone who can sign for that derived key's
|
/// this instruction allows someone who can sign for that derived key's
|
||||||
/// base key to authorize a new Voter or Withdrawer for a vote account.
|
/// base key to authorize a new Voter or Withdrawer for a vote account.
|
||||||
|
@ -370,6 +384,41 @@ pub fn update_vote_state_switch(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn compact_update_vote_state(
|
||||||
|
vote_pubkey: &Pubkey,
|
||||||
|
authorized_voter_pubkey: &Pubkey,
|
||||||
|
compact_vote_state_update: CompactVoteStateUpdate,
|
||||||
|
) -> Instruction {
|
||||||
|
let account_metas = vec![
|
||||||
|
AccountMeta::new(*vote_pubkey, false),
|
||||||
|
AccountMeta::new_readonly(*authorized_voter_pubkey, true),
|
||||||
|
];
|
||||||
|
|
||||||
|
Instruction::new_with_bincode(
|
||||||
|
id(),
|
||||||
|
&VoteInstruction::CompactUpdateVoteState(compact_vote_state_update),
|
||||||
|
account_metas,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compact_update_vote_state_switch(
|
||||||
|
vote_pubkey: &Pubkey,
|
||||||
|
authorized_voter_pubkey: &Pubkey,
|
||||||
|
vote_state_update: CompactVoteStateUpdate,
|
||||||
|
proof_hash: Hash,
|
||||||
|
) -> Instruction {
|
||||||
|
let account_metas = vec![
|
||||||
|
AccountMeta::new(*vote_pubkey, false),
|
||||||
|
AccountMeta::new_readonly(*authorized_voter_pubkey, true),
|
||||||
|
];
|
||||||
|
|
||||||
|
Instruction::new_with_bincode(
|
||||||
|
id(),
|
||||||
|
&VoteInstruction::CompactUpdateVoteStateSwitch(vote_state_update, proof_hash),
|
||||||
|
account_metas,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn withdraw(
|
pub fn withdraw(
|
||||||
vote_pubkey: &Pubkey,
|
vote_pubkey: &Pubkey,
|
||||||
authorized_withdrawer_pubkey: &Pubkey,
|
authorized_withdrawer_pubkey: &Pubkey,
|
||||||
|
|
|
@ -4,7 +4,7 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
id,
|
id,
|
||||||
vote_instruction::VoteInstruction,
|
vote_instruction::VoteInstruction,
|
||||||
vote_state::{self, VoteAuthorize},
|
vote_state::{self, VoteAuthorize, VoteStateUpdate},
|
||||||
},
|
},
|
||||||
log::*,
|
log::*,
|
||||||
solana_program_runtime::{
|
solana_program_runtime::{
|
||||||
|
@ -173,6 +173,31 @@ pub fn process_instruction(
|
||||||
Err(InstructionError::InvalidInstructionData)
|
Err(InstructionError::InvalidInstructionData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
VoteInstruction::CompactUpdateVoteState(compact_vote_state_update)
|
||||||
|
| VoteInstruction::CompactUpdateVoteStateSwitch(compact_vote_state_update, _) => {
|
||||||
|
if invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::allow_votes_to_directly_update_vote_state::id())
|
||||||
|
&& invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::compact_vote_state_updates::id())
|
||||||
|
{
|
||||||
|
let sysvar_cache = invoke_context.get_sysvar_cache();
|
||||||
|
let slot_hashes = sysvar_cache.get_slot_hashes()?;
|
||||||
|
let clock = sysvar_cache.get_clock()?;
|
||||||
|
vote_state::process_vote_state_update(
|
||||||
|
&mut me,
|
||||||
|
slot_hashes.slot_hashes(),
|
||||||
|
&clock,
|
||||||
|
VoteStateUpdate::from(compact_vote_state_update),
|
||||||
|
&signers,
|
||||||
|
&invoke_context.feature_set,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Err(InstructionError::InvalidInstructionData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VoteInstruction::Withdraw(lamports) => {
|
VoteInstruction::Withdraw(lamports) => {
|
||||||
instruction_context.check_number_of_instruction_accounts(2)?;
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||||
let rent_sysvar = invoke_context.get_sysvar_cache().get_rent()?;
|
let rent_sysvar = invoke_context.get_sysvar_cache().get_rent()?;
|
||||||
|
|
|
@ -7,7 +7,7 @@ use {
|
||||||
signature::Signature,
|
signature::Signature,
|
||||||
transaction::{SanitizedTransaction, Transaction},
|
transaction::{SanitizedTransaction, Transaction},
|
||||||
},
|
},
|
||||||
solana_vote_program::vote_instruction::VoteInstruction,
|
solana_vote_program::{vote_instruction::VoteInstruction, vote_state::VoteStateUpdate},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type ParsedVote = (Pubkey, VoteTransaction, Option<Hash>, Signature);
|
pub type ParsedVote = (Pubkey, VoteTransaction, Option<Hash>, Signature);
|
||||||
|
@ -29,6 +29,8 @@ pub(crate) fn is_simple_vote_transaction(transaction: &SanitizedTransaction) ->
|
||||||
| VoteInstruction::VoteSwitch(_, _)
|
| VoteInstruction::VoteSwitch(_, _)
|
||||||
| VoteInstruction::UpdateVoteState(_)
|
| VoteInstruction::UpdateVoteState(_)
|
||||||
| VoteInstruction::UpdateVoteStateSwitch(_, _)
|
| VoteInstruction::UpdateVoteStateSwitch(_, _)
|
||||||
|
| VoteInstruction::CompactUpdateVoteState(_)
|
||||||
|
| VoteInstruction::CompactUpdateVoteStateSwitch(..)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,6 +82,14 @@ fn parse_vote_instruction_data(
|
||||||
VoteInstruction::UpdateVoteStateSwitch(vote_state_update, hash) => {
|
VoteInstruction::UpdateVoteStateSwitch(vote_state_update, hash) => {
|
||||||
Some((VoteTransaction::from(vote_state_update), Some(hash)))
|
Some((VoteTransaction::from(vote_state_update), Some(hash)))
|
||||||
}
|
}
|
||||||
|
VoteInstruction::CompactUpdateVoteState(compact_vote_state_update) => Some((
|
||||||
|
VoteTransaction::from(VoteStateUpdate::from(compact_vote_state_update)),
|
||||||
|
None,
|
||||||
|
)),
|
||||||
|
VoteInstruction::CompactUpdateVoteStateSwitch(compact_vote_state_update, hash) => Some((
|
||||||
|
VoteTransaction::from(VoteStateUpdate::from(compact_vote_state_update)),
|
||||||
|
Some(hash),
|
||||||
|
)),
|
||||||
VoteInstruction::Authorize(_, _)
|
VoteInstruction::Authorize(_, _)
|
||||||
| VoteInstruction::AuthorizeChecked(_)
|
| VoteInstruction::AuthorizeChecked(_)
|
||||||
| VoteInstruction::AuthorizeWithSeed(_)
|
| VoteInstruction::AuthorizeWithSeed(_)
|
||||||
|
|
|
@ -476,6 +476,10 @@ pub mod use_default_units_in_fee_calculation {
|
||||||
solana_sdk::declare_id!("8sKQrMQoUHtQSUP83SPG4ta2JDjSAiWs7t5aJ9uEd6To");
|
solana_sdk::declare_id!("8sKQrMQoUHtQSUP83SPG4ta2JDjSAiWs7t5aJ9uEd6To");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod compact_vote_state_updates {
|
||||||
|
solana_sdk::declare_id!("86HpNqzutEZwLcPxS6EHDcMNYWk6ikhteg9un7Y2PBKE");
|
||||||
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// Map of feature identifiers to user-visible description
|
/// Map of feature identifiers to user-visible description
|
||||||
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
||||||
|
@ -589,6 +593,7 @@ lazy_static! {
|
||||||
(cap_bpf_program_instruction_accounts::id(), "enforce max number of accounts per bpf program instruction #26628"),
|
(cap_bpf_program_instruction_accounts::id(), "enforce max number of accounts per bpf program instruction #26628"),
|
||||||
(loosen_cpi_size_restriction::id(), "loosen cpi size restrictions #26641"),
|
(loosen_cpi_size_restriction::id(), "loosen cpi size restrictions #26641"),
|
||||||
(use_default_units_in_fee_calculation::id(), "use default units per instruction in fee calculation #26785"),
|
(use_default_units_in_fee_calculation::id(), "use default units per instruction in fee calculation #26785"),
|
||||||
|
(compact_vote_state_updates::id(), "Compact vote state updates to lower block size"),
|
||||||
/*************** ADD NEW FEATURES HERE ***************/
|
/*************** ADD NEW FEATURES HERE ***************/
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -5,7 +5,7 @@ use {
|
||||||
bincode::deserialize,
|
bincode::deserialize,
|
||||||
serde_json::json,
|
serde_json::json,
|
||||||
solana_sdk::{instruction::CompiledInstruction, message::AccountKeys},
|
solana_sdk::{instruction::CompiledInstruction, message::AccountKeys},
|
||||||
solana_vote_program::vote_instruction::VoteInstruction,
|
solana_vote_program::{vote_instruction::VoteInstruction, vote_state::VoteStateUpdate},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parse_vote(
|
pub fn parse_vote(
|
||||||
|
@ -101,7 +101,7 @@ pub fn parse_vote(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
VoteInstruction::UpdateVoteState(vote_state_update) => {
|
VoteInstruction::UpdateVoteState(vote_state_update) => {
|
||||||
check_num_vote_accounts(&instruction.accounts, 4)?;
|
check_num_vote_accounts(&instruction.accounts, 2)?;
|
||||||
let vote_state_update = json!({
|
let vote_state_update = json!({
|
||||||
"lockouts": vote_state_update.lockouts,
|
"lockouts": vote_state_update.lockouts,
|
||||||
"root": vote_state_update.root,
|
"root": vote_state_update.root,
|
||||||
|
@ -112,15 +112,13 @@ pub fn parse_vote(
|
||||||
instruction_type: "updatevotestate".to_string(),
|
instruction_type: "updatevotestate".to_string(),
|
||||||
info: json!({
|
info: json!({
|
||||||
"voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
|
"voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
|
||||||
"slotHashesSysvar": account_keys[instruction.accounts[1] as usize].to_string(),
|
"voteAuthority": account_keys[instruction.accounts[1] as usize].to_string(),
|
||||||
"clockSysvar": account_keys[instruction.accounts[2] as usize].to_string(),
|
|
||||||
"voteAuthority": account_keys[instruction.accounts[3] as usize].to_string(),
|
|
||||||
"voteStateUpdate": vote_state_update,
|
"voteStateUpdate": vote_state_update,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
VoteInstruction::UpdateVoteStateSwitch(vote_state_update, hash) => {
|
VoteInstruction::UpdateVoteStateSwitch(vote_state_update, hash) => {
|
||||||
check_num_vote_accounts(&instruction.accounts, 4)?;
|
check_num_vote_accounts(&instruction.accounts, 2)?;
|
||||||
let vote_state_update = json!({
|
let vote_state_update = json!({
|
||||||
"lockouts": vote_state_update.lockouts,
|
"lockouts": vote_state_update.lockouts,
|
||||||
"root": vote_state_update.root,
|
"root": vote_state_update.root,
|
||||||
|
@ -131,9 +129,44 @@ pub fn parse_vote(
|
||||||
instruction_type: "updatevotestateswitch".to_string(),
|
instruction_type: "updatevotestateswitch".to_string(),
|
||||||
info: json!({
|
info: json!({
|
||||||
"voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
|
"voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
|
||||||
"slotHashesSysvar": account_keys[instruction.accounts[1] as usize].to_string(),
|
"voteAuthority": account_keys[instruction.accounts[1] as usize].to_string(),
|
||||||
"clockSysvar": account_keys[instruction.accounts[2] as usize].to_string(),
|
"voteStateUpdate": vote_state_update,
|
||||||
"voteAuthority": account_keys[instruction.accounts[3] as usize].to_string(),
|
"hash": hash.to_string(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
VoteInstruction::CompactUpdateVoteState(compact_vote_state_update) => {
|
||||||
|
let vote_state_update = VoteStateUpdate::from(compact_vote_state_update);
|
||||||
|
check_num_vote_accounts(&instruction.accounts, 2)?;
|
||||||
|
let vote_state_update = json!({
|
||||||
|
"lockouts": vote_state_update.lockouts,
|
||||||
|
"root": vote_state_update.root,
|
||||||
|
"hash": vote_state_update.hash.to_string(),
|
||||||
|
"timestamp": vote_state_update.timestamp,
|
||||||
|
});
|
||||||
|
Ok(ParsedInstructionEnum {
|
||||||
|
instruction_type: "compactupdatevotestate".to_string(),
|
||||||
|
info: json!({
|
||||||
|
"voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
|
||||||
|
"voteAuthority": account_keys[instruction.accounts[1] as usize].to_string(),
|
||||||
|
"voteStateUpdate": vote_state_update,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
VoteInstruction::CompactUpdateVoteStateSwitch(compact_vote_state_update, hash) => {
|
||||||
|
let vote_state_update = VoteStateUpdate::from(compact_vote_state_update);
|
||||||
|
check_num_vote_accounts(&instruction.accounts, 2)?;
|
||||||
|
let vote_state_update = json!({
|
||||||
|
"lockouts": vote_state_update.lockouts,
|
||||||
|
"root": vote_state_update.root,
|
||||||
|
"hash": vote_state_update.hash.to_string(),
|
||||||
|
"timestamp": vote_state_update.timestamp,
|
||||||
|
});
|
||||||
|
Ok(ParsedInstructionEnum {
|
||||||
|
instruction_type: "compactupdatevotestateswitch".to_string(),
|
||||||
|
info: json!({
|
||||||
|
"voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
|
||||||
|
"voteAuthority": account_keys[instruction.accounts[1] as usize].to_string(),
|
||||||
"voteStateUpdate": vote_state_update,
|
"voteStateUpdate": vote_state_update,
|
||||||
"hash": hash.to_string(),
|
"hash": hash.to_string(),
|
||||||
}),
|
}),
|
||||||
|
@ -219,7 +252,7 @@ mod test {
|
||||||
solana_sdk::{hash::Hash, message::Message, pubkey::Pubkey, sysvar},
|
solana_sdk::{hash::Hash, message::Message, pubkey::Pubkey, sysvar},
|
||||||
solana_vote_program::{
|
solana_vote_program::{
|
||||||
vote_instruction,
|
vote_instruction,
|
||||||
vote_state::{Vote, VoteAuthorize, VoteInit},
|
vote_state::{CompactVoteStateUpdate, Vote, VoteAuthorize, VoteInit},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -642,4 +675,180 @@ mod test {
|
||||||
message.instructions[0].accounts.pop();
|
message.instructions[0].accounts.pop();
|
||||||
assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err());
|
assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_vote_state_update_ix() {
|
||||||
|
let vote_state_update = VoteStateUpdate::from(vec![(0, 3), (1, 2), (2, 1)]);
|
||||||
|
|
||||||
|
let vote_pubkey = Pubkey::new_unique();
|
||||||
|
let authorized_voter_pubkey = Pubkey::new_unique();
|
||||||
|
let instruction = vote_instruction::update_vote_state(
|
||||||
|
&vote_pubkey,
|
||||||
|
&authorized_voter_pubkey,
|
||||||
|
vote_state_update.clone(),
|
||||||
|
);
|
||||||
|
let mut message = Message::new(&[instruction], None);
|
||||||
|
assert_eq!(
|
||||||
|
parse_vote(
|
||||||
|
&message.instructions[0],
|
||||||
|
&AccountKeys::new(&message.account_keys, None)
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
ParsedInstructionEnum {
|
||||||
|
instruction_type: "updatevotestate".to_string(),
|
||||||
|
info: json!({
|
||||||
|
"voteAccount": vote_pubkey.to_string(),
|
||||||
|
"voteAuthority": authorized_voter_pubkey.to_string(),
|
||||||
|
"voteStateUpdate": {
|
||||||
|
"lockouts": vote_state_update.lockouts,
|
||||||
|
"root": None::<u64>,
|
||||||
|
"hash": Hash::default().to_string(),
|
||||||
|
"timestamp": None::<u64>,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert!(parse_vote(
|
||||||
|
&message.instructions[0],
|
||||||
|
&AccountKeys::new(&message.account_keys[0..1], None)
|
||||||
|
)
|
||||||
|
.is_err());
|
||||||
|
let keys = message.account_keys.clone();
|
||||||
|
message.instructions[0].accounts.pop();
|
||||||
|
assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_vote_state_update_switch_ix() {
|
||||||
|
let vote_state_update = VoteStateUpdate::from(vec![(0, 3), (1, 2), (2, 1)]);
|
||||||
|
|
||||||
|
let vote_pubkey = Pubkey::new_unique();
|
||||||
|
let authorized_voter_pubkey = Pubkey::new_unique();
|
||||||
|
let proof_hash = Hash::new_from_array([2; 32]);
|
||||||
|
let instruction = vote_instruction::update_vote_state_switch(
|
||||||
|
&vote_pubkey,
|
||||||
|
&authorized_voter_pubkey,
|
||||||
|
vote_state_update.clone(),
|
||||||
|
proof_hash,
|
||||||
|
);
|
||||||
|
let mut message = Message::new(&[instruction], None);
|
||||||
|
assert_eq!(
|
||||||
|
parse_vote(
|
||||||
|
&message.instructions[0],
|
||||||
|
&AccountKeys::new(&message.account_keys, None)
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
ParsedInstructionEnum {
|
||||||
|
instruction_type: "updatevotestateswitch".to_string(),
|
||||||
|
info: json!({
|
||||||
|
"voteAccount": vote_pubkey.to_string(),
|
||||||
|
"voteAuthority": authorized_voter_pubkey.to_string(),
|
||||||
|
"voteStateUpdate": {
|
||||||
|
"lockouts": vote_state_update.lockouts,
|
||||||
|
"root": None::<u64>,
|
||||||
|
"hash": Hash::default().to_string(),
|
||||||
|
"timestamp": None::<u64>,
|
||||||
|
},
|
||||||
|
"hash": proof_hash.to_string(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert!(parse_vote(
|
||||||
|
&message.instructions[0],
|
||||||
|
&AccountKeys::new(&message.account_keys[0..1], None)
|
||||||
|
)
|
||||||
|
.is_err());
|
||||||
|
let keys = message.account_keys.clone();
|
||||||
|
message.instructions[0].accounts.pop();
|
||||||
|
assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_compact_vote_state_update_ix() {
|
||||||
|
let vote_state_update = VoteStateUpdate::from(vec![(0, 3), (1, 2), (2, 1)]);
|
||||||
|
let compact_vote_state_update = CompactVoteStateUpdate::from(vote_state_update.clone());
|
||||||
|
|
||||||
|
let vote_pubkey = Pubkey::new_unique();
|
||||||
|
let authorized_voter_pubkey = Pubkey::new_unique();
|
||||||
|
let instruction = vote_instruction::compact_update_vote_state(
|
||||||
|
&vote_pubkey,
|
||||||
|
&authorized_voter_pubkey,
|
||||||
|
compact_vote_state_update,
|
||||||
|
);
|
||||||
|
let mut message = Message::new(&[instruction], None);
|
||||||
|
assert_eq!(
|
||||||
|
parse_vote(
|
||||||
|
&message.instructions[0],
|
||||||
|
&AccountKeys::new(&message.account_keys, None)
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
ParsedInstructionEnum {
|
||||||
|
instruction_type: "compactupdatevotestate".to_string(),
|
||||||
|
info: json!({
|
||||||
|
"voteAccount": vote_pubkey.to_string(),
|
||||||
|
"voteAuthority": authorized_voter_pubkey.to_string(),
|
||||||
|
"voteStateUpdate": {
|
||||||
|
"lockouts": vote_state_update.lockouts,
|
||||||
|
"root": None::<u64>,
|
||||||
|
"hash": Hash::default().to_string(),
|
||||||
|
"timestamp": None::<u64>,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert!(parse_vote(
|
||||||
|
&message.instructions[0],
|
||||||
|
&AccountKeys::new(&message.account_keys[0..1], None)
|
||||||
|
)
|
||||||
|
.is_err());
|
||||||
|
let keys = message.account_keys.clone();
|
||||||
|
message.instructions[0].accounts.pop();
|
||||||
|
assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_compact_vote_state_update_switch_ix() {
|
||||||
|
let vote_state_update = VoteStateUpdate::from(vec![(0, 3), (1, 2), (2, 1)]);
|
||||||
|
let compact_vote_state_update = CompactVoteStateUpdate::from(vote_state_update.clone());
|
||||||
|
|
||||||
|
let vote_pubkey = Pubkey::new_unique();
|
||||||
|
let authorized_voter_pubkey = Pubkey::new_unique();
|
||||||
|
let proof_hash = Hash::new_from_array([2; 32]);
|
||||||
|
let instruction = vote_instruction::compact_update_vote_state_switch(
|
||||||
|
&vote_pubkey,
|
||||||
|
&authorized_voter_pubkey,
|
||||||
|
compact_vote_state_update,
|
||||||
|
proof_hash,
|
||||||
|
);
|
||||||
|
let mut message = Message::new(&[instruction], None);
|
||||||
|
assert_eq!(
|
||||||
|
parse_vote(
|
||||||
|
&message.instructions[0],
|
||||||
|
&AccountKeys::new(&message.account_keys, None)
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
ParsedInstructionEnum {
|
||||||
|
instruction_type: "compactupdatevotestateswitch".to_string(),
|
||||||
|
info: json!({
|
||||||
|
"voteAccount": vote_pubkey.to_string(),
|
||||||
|
"voteAuthority": authorized_voter_pubkey.to_string(),
|
||||||
|
"voteStateUpdate": {
|
||||||
|
"lockouts": vote_state_update.lockouts,
|
||||||
|
"root": None::<u64>,
|
||||||
|
"hash": Hash::default().to_string(),
|
||||||
|
"timestamp": None::<u64>,
|
||||||
|
},
|
||||||
|
"hash": proof_hash.to_string(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert!(parse_vote(
|
||||||
|
&message.instructions[0],
|
||||||
|
&AccountKeys::new(&message.account_keys[0..1], None)
|
||||||
|
)
|
||||||
|
.is_err());
|
||||||
|
let keys = message.account_keys.clone();
|
||||||
|
message.instructions[0].accounts.pop();
|
||||||
|
assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue