1use {
2 crate::parse_instruction::{
3 check_num_accounts, ParsableProgram, ParseInstructionError, ParsedInstructionEnum,
4 },
5 bincode::deserialize,
6 serde_json::json,
7 solana_message::{compiled_instruction::CompiledInstruction, AccountKeys},
8 solana_program::vote::instruction::VoteInstruction,
9};
10
11pub fn parse_vote(
12 instruction: &CompiledInstruction,
13 account_keys: &AccountKeys,
14) -> Result<ParsedInstructionEnum, ParseInstructionError> {
15 let vote_instruction: VoteInstruction = deserialize(&instruction.data)
16 .map_err(|_| ParseInstructionError::InstructionNotParsable(ParsableProgram::Vote))?;
17 match instruction.accounts.iter().max() {
18 Some(index) if (*index as usize) < account_keys.len() => {}
19 _ => {
20 return Err(ParseInstructionError::InstructionKeyMismatch(
22 ParsableProgram::Vote,
23 ));
24 }
25 }
26 match vote_instruction {
27 VoteInstruction::InitializeAccount(vote_init) => {
28 check_num_vote_accounts(&instruction.accounts, 4)?;
29 Ok(ParsedInstructionEnum {
30 instruction_type: "initialize".to_string(),
31 info: json!({
32 "voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
33 "rentSysvar": account_keys[instruction.accounts[1] as usize].to_string(),
34 "clockSysvar": account_keys[instruction.accounts[2] as usize].to_string(),
35 "node": account_keys[instruction.accounts[3] as usize].to_string(),
36 "authorizedVoter": vote_init.authorized_voter.to_string(),
37 "authorizedWithdrawer": vote_init.authorized_withdrawer.to_string(),
38 "commission": vote_init.commission,
39 }),
40 })
41 }
42 VoteInstruction::Authorize(new_authorized, authority_type) => {
43 check_num_vote_accounts(&instruction.accounts, 3)?;
44 Ok(ParsedInstructionEnum {
45 instruction_type: "authorize".to_string(),
46 info: json!({
47 "voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
48 "clockSysvar": account_keys[instruction.accounts[1] as usize].to_string(),
49 "authority": account_keys[instruction.accounts[2] as usize].to_string(),
50 "newAuthority": new_authorized.to_string(),
51 "authorityType": authority_type,
52 }),
53 })
54 }
55 VoteInstruction::AuthorizeWithSeed(args) => {
56 check_num_vote_accounts(&instruction.accounts, 3)?;
57 Ok(ParsedInstructionEnum {
58 instruction_type: "authorizeWithSeed".to_string(),
59 info: json!({
60 "voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
61 "clockSysvar": account_keys[instruction.accounts[1] as usize].to_string(),
62 "authorityBaseKey": account_keys[instruction.accounts[2] as usize].to_string(),
63 "authorityOwner": args.current_authority_derived_key_owner.to_string(),
64 "authoritySeed": args.current_authority_derived_key_seed,
65 "newAuthority": args.new_authority.to_string(),
66 "authorityType": args.authorization_type,
67 }),
68 })
69 }
70 VoteInstruction::AuthorizeCheckedWithSeed(args) => {
71 check_num_vote_accounts(&instruction.accounts, 4)?;
72 Ok(ParsedInstructionEnum {
73 instruction_type: "authorizeCheckedWithSeed".to_string(),
74 info: json!({
75 "voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
76 "clockSysvar": account_keys[instruction.accounts[1] as usize].to_string(),
77 "authorityBaseKey": account_keys[instruction.accounts[2] as usize].to_string(),
78 "authorityOwner": args.current_authority_derived_key_owner.to_string(),
79 "authoritySeed": args.current_authority_derived_key_seed,
80 "newAuthority": account_keys[instruction.accounts[3] as usize].to_string(),
81 "authorityType": args.authorization_type,
82 }),
83 })
84 }
85 VoteInstruction::Vote(vote) => {
86 check_num_vote_accounts(&instruction.accounts, 4)?;
87 let vote = json!({
88 "slots": vote.slots,
89 "hash": vote.hash.to_string(),
90 "timestamp": vote.timestamp,
91 });
92 Ok(ParsedInstructionEnum {
93 instruction_type: "vote".to_string(),
94 info: json!({
95 "voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
96 "slotHashesSysvar": account_keys[instruction.accounts[1] as usize].to_string(),
97 "clockSysvar": account_keys[instruction.accounts[2] as usize].to_string(),
98 "voteAuthority": account_keys[instruction.accounts[3] as usize].to_string(),
99 "vote": vote,
100 }),
101 })
102 }
103 VoteInstruction::UpdateVoteState(vote_state_update) => {
104 check_num_vote_accounts(&instruction.accounts, 2)?;
105 let vote_state_update = json!({
106 "lockouts": vote_state_update.lockouts,
107 "root": vote_state_update.root,
108 "hash": vote_state_update.hash.to_string(),
109 "timestamp": vote_state_update.timestamp,
110 });
111 Ok(ParsedInstructionEnum {
112 instruction_type: "updatevotestate".to_string(),
113 info: json!({
114 "voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
115 "voteAuthority": account_keys[instruction.accounts[1] as usize].to_string(),
116 "voteStateUpdate": vote_state_update,
117 }),
118 })
119 }
120 VoteInstruction::UpdateVoteStateSwitch(vote_state_update, hash) => {
121 check_num_vote_accounts(&instruction.accounts, 2)?;
122 let vote_state_update = json!({
123 "lockouts": vote_state_update.lockouts,
124 "root": vote_state_update.root,
125 "hash": vote_state_update.hash.to_string(),
126 "timestamp": vote_state_update.timestamp,
127 });
128 Ok(ParsedInstructionEnum {
129 instruction_type: "updatevotestateswitch".to_string(),
130 info: json!({
131 "voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
132 "voteAuthority": account_keys[instruction.accounts[1] as usize].to_string(),
133 "voteStateUpdate": vote_state_update,
134 "hash": hash.to_string(),
135 }),
136 })
137 }
138 VoteInstruction::CompactUpdateVoteState(vote_state_update) => {
139 check_num_vote_accounts(&instruction.accounts, 2)?;
140 let vote_state_update = json!({
141 "lockouts": vote_state_update.lockouts,
142 "root": vote_state_update.root,
143 "hash": vote_state_update.hash.to_string(),
144 "timestamp": vote_state_update.timestamp,
145 });
146 Ok(ParsedInstructionEnum {
147 instruction_type: "compactupdatevotestate".to_string(),
148 info: json!({
149 "voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
150 "voteAuthority": account_keys[instruction.accounts[1] as usize].to_string(),
151 "voteStateUpdate": vote_state_update,
152 }),
153 })
154 }
155 VoteInstruction::CompactUpdateVoteStateSwitch(vote_state_update, hash) => {
156 check_num_vote_accounts(&instruction.accounts, 2)?;
157 let vote_state_update = json!({
158 "lockouts": vote_state_update.lockouts,
159 "root": vote_state_update.root,
160 "hash": vote_state_update.hash.to_string(),
161 "timestamp": vote_state_update.timestamp,
162 });
163 Ok(ParsedInstructionEnum {
164 instruction_type: "compactupdatevotestateswitch".to_string(),
165 info: json!({
166 "voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
167 "voteAuthority": account_keys[instruction.accounts[1] as usize].to_string(),
168 "voteStateUpdate": vote_state_update,
169 "hash": hash.to_string(),
170 }),
171 })
172 }
173 VoteInstruction::TowerSync(tower_sync) => {
174 check_num_vote_accounts(&instruction.accounts, 2)?;
175 let tower_sync = json!({
176 "lockouts": tower_sync.lockouts,
177 "root": tower_sync.root,
178 "hash": tower_sync.hash.to_string(),
179 "timestamp": tower_sync.timestamp,
180 "blockId": tower_sync.block_id.to_string(),
181 });
182 Ok(ParsedInstructionEnum {
183 instruction_type: "towersync".to_string(),
184 info: json!({
185 "voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
186 "voteAuthority": account_keys[instruction.accounts[1] as usize].to_string(),
187 "towerSync": tower_sync,
188 }),
189 })
190 }
191 VoteInstruction::TowerSyncSwitch(tower_sync, hash) => {
192 check_num_vote_accounts(&instruction.accounts, 2)?;
193 let tower_sync = json!({
194 "lockouts": tower_sync.lockouts,
195 "root": tower_sync.root,
196 "hash": tower_sync.hash.to_string(),
197 "timestamp": tower_sync.timestamp,
198 "blockId": tower_sync.block_id.to_string(),
199 });
200 Ok(ParsedInstructionEnum {
201 instruction_type: "towersyncswitch".to_string(),
202 info: json!({
203 "voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
204 "voteAuthority": account_keys[instruction.accounts[1] as usize].to_string(),
205 "towerSync": tower_sync,
206 "hash": hash.to_string(),
207 }),
208 })
209 }
210 VoteInstruction::Withdraw(lamports) => {
211 check_num_vote_accounts(&instruction.accounts, 3)?;
212 Ok(ParsedInstructionEnum {
213 instruction_type: "withdraw".to_string(),
214 info: json!({
215 "voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
216 "destination": account_keys[instruction.accounts[1] as usize].to_string(),
217 "withdrawAuthority": account_keys[instruction.accounts[2] as usize].to_string(),
218 "lamports": lamports,
219 }),
220 })
221 }
222 VoteInstruction::UpdateValidatorIdentity => {
223 check_num_vote_accounts(&instruction.accounts, 3)?;
224 Ok(ParsedInstructionEnum {
225 instruction_type: "updateValidatorIdentity".to_string(),
226 info: json!({
227 "voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
228 "newValidatorIdentity": account_keys[instruction.accounts[1] as usize].to_string(),
229 "withdrawAuthority": account_keys[instruction.accounts[2] as usize].to_string(),
230 }),
231 })
232 }
233 VoteInstruction::UpdateCommission(commission) => {
234 check_num_vote_accounts(&instruction.accounts, 2)?;
235 Ok(ParsedInstructionEnum {
236 instruction_type: "updateCommission".to_string(),
237 info: json!({
238 "voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
239 "withdrawAuthority": account_keys[instruction.accounts[1] as usize].to_string(),
240 "commission": commission,
241 }),
242 })
243 }
244 VoteInstruction::VoteSwitch(vote, hash) => {
245 check_num_vote_accounts(&instruction.accounts, 4)?;
246 let vote = json!({
247 "slots": vote.slots,
248 "hash": vote.hash.to_string(),
249 "timestamp": vote.timestamp,
250 });
251 Ok(ParsedInstructionEnum {
252 instruction_type: "voteSwitch".to_string(),
253 info: json!({
254 "voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
255 "slotHashesSysvar": account_keys[instruction.accounts[1] as usize].to_string(),
256 "clockSysvar": account_keys[instruction.accounts[2] as usize].to_string(),
257 "voteAuthority": account_keys[instruction.accounts[3] as usize].to_string(),
258 "vote": vote,
259 "hash": hash.to_string(),
260 }),
261 })
262 }
263 VoteInstruction::AuthorizeChecked(authority_type) => {
264 check_num_vote_accounts(&instruction.accounts, 4)?;
265 Ok(ParsedInstructionEnum {
266 instruction_type: "authorizeChecked".to_string(),
267 info: json!({
268 "voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
269 "clockSysvar": account_keys[instruction.accounts[1] as usize].to_string(),
270 "authority": account_keys[instruction.accounts[2] as usize].to_string(),
271 "newAuthority": account_keys[instruction.accounts[3] as usize].to_string(),
272 "authorityType": authority_type,
273 }),
274 })
275 }
276 }
277}
278
279fn check_num_vote_accounts(accounts: &[u8], num: usize) -> Result<(), ParseInstructionError> {
280 check_num_accounts(accounts, num, ParsableProgram::Vote)
281}
282
283#[cfg(test)]
284mod test {
285 use {
286 super::*,
287 solana_hash::Hash,
288 solana_message::Message,
289 solana_program::vote::{
290 instruction as vote_instruction,
291 state::{TowerSync, Vote, VoteAuthorize, VoteInit, VoteStateUpdate, VoteStateVersions},
292 },
293 solana_pubkey::Pubkey,
294 solana_sdk_ids::sysvar,
295 };
296
297 #[test]
298 fn test_parse_vote_initialize_ix() {
299 let lamports = 55;
300
301 let commission = 10;
302 let node_pubkey = Pubkey::new_unique();
303 let vote_pubkey = Pubkey::new_unique();
304 let authorized_voter = Pubkey::new_unique();
305 let authorized_withdrawer = Pubkey::new_unique();
306 let vote_init = VoteInit {
307 node_pubkey,
308 authorized_voter,
309 authorized_withdrawer,
310 commission,
311 };
312
313 let instructions = vote_instruction::create_account_with_config(
314 &Pubkey::new_unique(),
315 &vote_pubkey,
316 &vote_init,
317 lamports,
318 vote_instruction::CreateVoteAccountConfig {
319 space: VoteStateVersions::vote_state_size_of(true) as u64,
320 ..vote_instruction::CreateVoteAccountConfig::default()
321 },
322 );
323 let mut message = Message::new(&instructions, None);
324 assert_eq!(
325 parse_vote(
326 &message.instructions[1],
327 &AccountKeys::new(&message.account_keys, None)
328 )
329 .unwrap(),
330 ParsedInstructionEnum {
331 instruction_type: "initialize".to_string(),
332 info: json!({
333 "voteAccount": vote_pubkey.to_string(),
334 "rentSysvar": sysvar::rent::ID.to_string(),
335 "clockSysvar": sysvar::clock::ID.to_string(),
336 "node": node_pubkey.to_string(),
337 "authorizedVoter": authorized_voter.to_string(),
338 "authorizedWithdrawer": authorized_withdrawer.to_string(),
339 "commission": commission,
340 }),
341 }
342 );
343 assert!(parse_vote(
344 &message.instructions[1],
345 &AccountKeys::new(&message.account_keys[0..3], None)
346 )
347 .is_err());
348 let keys = message.account_keys.clone();
349 message.instructions[0].accounts.pop();
350 assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err());
351 }
352
353 #[test]
354 fn test_parse_vote_authorize_ix() {
355 let vote_pubkey = Pubkey::new_unique();
356 let authorized_pubkey = Pubkey::new_unique();
357 let new_authorized_pubkey = Pubkey::new_unique();
358 let authority_type = VoteAuthorize::Voter;
359 let instruction = vote_instruction::authorize(
360 &vote_pubkey,
361 &authorized_pubkey,
362 &new_authorized_pubkey,
363 authority_type,
364 );
365 let mut message = Message::new(&[instruction], None);
366 assert_eq!(
367 parse_vote(
368 &message.instructions[0],
369 &AccountKeys::new(&message.account_keys, None)
370 )
371 .unwrap(),
372 ParsedInstructionEnum {
373 instruction_type: "authorize".to_string(),
374 info: json!({
375 "voteAccount": vote_pubkey.to_string(),
376 "clockSysvar": sysvar::clock::ID.to_string(),
377 "authority": authorized_pubkey.to_string(),
378 "newAuthority": new_authorized_pubkey.to_string(),
379 "authorityType": authority_type,
380 }),
381 }
382 );
383 assert!(parse_vote(
384 &message.instructions[0],
385 &AccountKeys::new(&message.account_keys[0..2], None)
386 )
387 .is_err());
388 let keys = message.account_keys.clone();
389 message.instructions[0].accounts.pop();
390 assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err());
391 }
392
393 #[test]
394 fn test_parse_vote_authorize_with_seed_ix() {
395 let vote_pubkey = Pubkey::new_unique();
396 let authorized_base_key = Pubkey::new_unique();
397 let new_authorized_pubkey = Pubkey::new_unique();
398 let authority_type = VoteAuthorize::Voter;
399 let current_authority_owner = Pubkey::new_unique();
400 let current_authority_seed = "AUTHORITY_SEED";
401 let instruction = vote_instruction::authorize_with_seed(
402 &vote_pubkey,
403 &authorized_base_key,
404 ¤t_authority_owner,
405 current_authority_seed,
406 &new_authorized_pubkey,
407 authority_type,
408 );
409 let message = Message::new(&[instruction], None);
410 assert_eq!(
411 parse_vote(
412 &message.instructions[0],
413 &AccountKeys::new(&message.account_keys, None)
414 )
415 .unwrap(),
416 ParsedInstructionEnum {
417 instruction_type: "authorizeWithSeed".to_string(),
418 info: json!({
419 "voteAccount": vote_pubkey.to_string(),
420 "clockSysvar": sysvar::clock::ID.to_string(),
421 "authorityBaseKey": authorized_base_key.to_string(),
422 "authorityOwner": current_authority_owner.to_string(),
423 "authoritySeed": current_authority_seed,
424 "newAuthority": new_authorized_pubkey.to_string(),
425 "authorityType": authority_type,
426 }),
427 }
428 );
429 assert!(parse_vote(
430 &message.instructions[0],
431 &AccountKeys::new(&message.account_keys[0..2], None)
432 )
433 .is_err());
434 }
435
436 #[test]
437 fn test_parse_vote_authorize_with_seed_checked_ix() {
438 let vote_pubkey = Pubkey::new_unique();
439 let authorized_base_key = Pubkey::new_unique();
440 let new_authorized_pubkey = Pubkey::new_unique();
441 let authority_type = VoteAuthorize::Voter;
442 let current_authority_owner = Pubkey::new_unique();
443 let current_authority_seed = "AUTHORITY_SEED";
444 let instruction = vote_instruction::authorize_checked_with_seed(
445 &vote_pubkey,
446 &authorized_base_key,
447 ¤t_authority_owner,
448 current_authority_seed,
449 &new_authorized_pubkey,
450 authority_type,
451 );
452 let message = Message::new(&[instruction], None);
453 assert_eq!(
454 parse_vote(
455 &message.instructions[0],
456 &AccountKeys::new(&message.account_keys, None)
457 )
458 .unwrap(),
459 ParsedInstructionEnum {
460 instruction_type: "authorizeCheckedWithSeed".to_string(),
461 info: json!({
462 "voteAccount": vote_pubkey.to_string(),
463 "clockSysvar": sysvar::clock::ID.to_string(),
464 "authorityBaseKey": authorized_base_key.to_string(),
465 "authorityOwner": current_authority_owner.to_string(),
466 "authoritySeed": current_authority_seed,
467 "newAuthority": new_authorized_pubkey.to_string(),
468 "authorityType": authority_type,
469 }),
470 }
471 );
472 assert!(parse_vote(
473 &message.instructions[0],
474 &AccountKeys::new(&message.account_keys[0..3], None)
475 )
476 .is_err());
477 }
478
479 #[test]
480 fn test_parse_vote_ix() {
481 let hash = Hash::new_from_array([1; 32]);
482 let vote = Vote {
483 slots: vec![1, 2, 4],
484 hash,
485 timestamp: Some(1_234_567_890),
486 };
487
488 let vote_pubkey = Pubkey::new_unique();
489 let authorized_voter_pubkey = Pubkey::new_unique();
490 let instruction = vote_instruction::vote(&vote_pubkey, &authorized_voter_pubkey, vote);
491 let mut message = Message::new(&[instruction], None);
492 assert_eq!(
493 parse_vote(
494 &message.instructions[0],
495 &AccountKeys::new(&message.account_keys, None)
496 )
497 .unwrap(),
498 ParsedInstructionEnum {
499 instruction_type: "vote".to_string(),
500 info: json!({
501 "voteAccount": vote_pubkey.to_string(),
502 "slotHashesSysvar": sysvar::slot_hashes::ID.to_string(),
503 "clockSysvar": sysvar::clock::ID.to_string(),
504 "voteAuthority": authorized_voter_pubkey.to_string(),
505 "vote": {
506 "slots": [1, 2, 4],
507 "hash": hash.to_string(),
508 "timestamp": 1_234_567_890,
509 },
510 }),
511 }
512 );
513 assert!(parse_vote(
514 &message.instructions[0],
515 &AccountKeys::new(&message.account_keys[0..3], None)
516 )
517 .is_err());
518 let keys = message.account_keys.clone();
519 message.instructions[0].accounts.pop();
520 assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err());
521 }
522
523 #[test]
524 fn test_parse_vote_withdraw_ix() {
525 let lamports = 55;
526 let vote_pubkey = Pubkey::new_unique();
527 let authorized_withdrawer_pubkey = Pubkey::new_unique();
528 let to_pubkey = Pubkey::new_unique();
529 let instruction = vote_instruction::withdraw(
530 &vote_pubkey,
531 &authorized_withdrawer_pubkey,
532 lamports,
533 &to_pubkey,
534 );
535 let mut message = Message::new(&[instruction], None);
536 assert_eq!(
537 parse_vote(
538 &message.instructions[0],
539 &AccountKeys::new(&message.account_keys, None)
540 )
541 .unwrap(),
542 ParsedInstructionEnum {
543 instruction_type: "withdraw".to_string(),
544 info: json!({
545 "voteAccount": vote_pubkey.to_string(),
546 "destination": to_pubkey.to_string(),
547 "withdrawAuthority": authorized_withdrawer_pubkey.to_string(),
548 "lamports": lamports,
549 }),
550 }
551 );
552 assert!(parse_vote(
553 &message.instructions[0],
554 &AccountKeys::new(&message.account_keys[0..2], None)
555 )
556 .is_err());
557 let keys = message.account_keys.clone();
558 message.instructions[0].accounts.pop();
559 assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err());
560 }
561
562 #[test]
563 fn test_parse_vote_update_validator_identity_ix() {
564 let vote_pubkey = Pubkey::new_unique();
565 let authorized_withdrawer_pubkey = Pubkey::new_unique();
566 let node_pubkey = Pubkey::new_unique();
567 let instruction = vote_instruction::update_validator_identity(
568 &vote_pubkey,
569 &authorized_withdrawer_pubkey,
570 &node_pubkey,
571 );
572 let mut message = Message::new(&[instruction], None);
573 assert_eq!(
574 parse_vote(
575 &message.instructions[0],
576 &AccountKeys::new(&message.account_keys, None)
577 )
578 .unwrap(),
579 ParsedInstructionEnum {
580 instruction_type: "updateValidatorIdentity".to_string(),
581 info: json!({
582 "voteAccount": vote_pubkey.to_string(),
583 "newValidatorIdentity": node_pubkey.to_string(),
584 "withdrawAuthority": authorized_withdrawer_pubkey.to_string(),
585 }),
586 }
587 );
588 assert!(parse_vote(
589 &message.instructions[0],
590 &AccountKeys::new(&message.account_keys[0..2], None)
591 )
592 .is_err());
593 let keys = message.account_keys.clone();
594 message.instructions[0].accounts.pop();
595 assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err());
596 }
597
598 #[test]
599 fn test_parse_vote_update_commission_ix() {
600 let commission = 10;
601 let vote_pubkey = Pubkey::new_unique();
602 let authorized_withdrawer_pubkey = Pubkey::new_unique();
603 let instruction = vote_instruction::update_commission(
604 &vote_pubkey,
605 &authorized_withdrawer_pubkey,
606 commission,
607 );
608 let mut message = Message::new(&[instruction], None);
609 assert_eq!(
610 parse_vote(
611 &message.instructions[0],
612 &AccountKeys::new(&message.account_keys, None)
613 )
614 .unwrap(),
615 ParsedInstructionEnum {
616 instruction_type: "updateCommission".to_string(),
617 info: json!({
618 "voteAccount": vote_pubkey.to_string(),
619 "withdrawAuthority": authorized_withdrawer_pubkey.to_string(),
620 "commission": commission,
621 }),
622 }
623 );
624 assert!(parse_vote(
625 &message.instructions[0],
626 &AccountKeys::new(&message.account_keys[0..1], None)
627 )
628 .is_err());
629 let keys = message.account_keys.clone();
630 message.instructions[0].accounts.pop();
631 assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err());
632 }
633
634 #[test]
635 fn test_parse_vote_switch_ix() {
636 let hash = Hash::new_from_array([1; 32]);
637 let vote = Vote {
638 slots: vec![1, 2, 4],
639 hash,
640 timestamp: Some(1_234_567_890),
641 };
642
643 let vote_pubkey = Pubkey::new_unique();
644 let authorized_voter_pubkey = Pubkey::new_unique();
645 let proof_hash = Hash::new_from_array([2; 32]);
646 let instruction =
647 vote_instruction::vote_switch(&vote_pubkey, &authorized_voter_pubkey, vote, proof_hash);
648 let mut message = Message::new(&[instruction], None);
649 assert_eq!(
650 parse_vote(
651 &message.instructions[0],
652 &AccountKeys::new(&message.account_keys, None)
653 )
654 .unwrap(),
655 ParsedInstructionEnum {
656 instruction_type: "voteSwitch".to_string(),
657 info: json!({
658 "voteAccount": vote_pubkey.to_string(),
659 "slotHashesSysvar": sysvar::slot_hashes::ID.to_string(),
660 "clockSysvar": sysvar::clock::ID.to_string(),
661 "voteAuthority": authorized_voter_pubkey.to_string(),
662 "vote": {
663 "slots": [1, 2, 4],
664 "hash": hash.to_string(),
665 "timestamp": 1_234_567_890,
666 },
667 "hash": proof_hash.to_string(),
668 }),
669 }
670 );
671 assert!(parse_vote(
672 &message.instructions[0],
673 &AccountKeys::new(&message.account_keys[0..3], None)
674 )
675 .is_err());
676 let keys = message.account_keys.clone();
677 message.instructions[0].accounts.pop();
678 assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err());
679 }
680
681 #[test]
682 fn test_parse_vote_authorized_checked_ix() {
683 let vote_pubkey = Pubkey::new_unique();
684 let authorized_pubkey = Pubkey::new_unique();
685 let new_authorized_pubkey = Pubkey::new_unique();
686 let authority_type = VoteAuthorize::Voter;
687 let instruction = vote_instruction::authorize_checked(
688 &vote_pubkey,
689 &authorized_pubkey,
690 &new_authorized_pubkey,
691 authority_type,
692 );
693 let mut message = Message::new(&[instruction], None);
694 assert_eq!(
695 parse_vote(
696 &message.instructions[0],
697 &AccountKeys::new(&message.account_keys, None)
698 )
699 .unwrap(),
700 ParsedInstructionEnum {
701 instruction_type: "authorizeChecked".to_string(),
702 info: json!({
703 "voteAccount": vote_pubkey.to_string(),
704 "clockSysvar": sysvar::clock::ID.to_string(),
705 "authority": authorized_pubkey.to_string(),
706 "newAuthority": new_authorized_pubkey.to_string(),
707 "authorityType": authority_type,
708 }),
709 }
710 );
711 assert!(parse_vote(
712 &message.instructions[0],
713 &AccountKeys::new(&message.account_keys[0..3], None)
714 )
715 .is_err());
716 let keys = message.account_keys.clone();
717 message.instructions[0].accounts.pop();
718 assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err());
719 }
720
721 #[test]
722 fn test_parse_vote_state_update_ix() {
723 let vote_state_update = VoteStateUpdate::from(vec![(0, 3), (1, 2), (2, 1)]);
724
725 let vote_pubkey = Pubkey::new_unique();
726 let authorized_voter_pubkey = Pubkey::new_unique();
727 let instruction = vote_instruction::update_vote_state(
728 &vote_pubkey,
729 &authorized_voter_pubkey,
730 vote_state_update.clone(),
731 );
732 let mut message = Message::new(&[instruction], None);
733 assert_eq!(
734 parse_vote(
735 &message.instructions[0],
736 &AccountKeys::new(&message.account_keys, None)
737 )
738 .unwrap(),
739 ParsedInstructionEnum {
740 instruction_type: "updatevotestate".to_string(),
741 info: json!({
742 "voteAccount": vote_pubkey.to_string(),
743 "voteAuthority": authorized_voter_pubkey.to_string(),
744 "voteStateUpdate": {
745 "lockouts": vote_state_update.lockouts,
746 "root": None::<u64>,
747 "hash": Hash::default().to_string(),
748 "timestamp": None::<u64>,
749 },
750 }),
751 }
752 );
753 assert!(parse_vote(
754 &message.instructions[0],
755 &AccountKeys::new(&message.account_keys[0..1], None)
756 )
757 .is_err());
758 let keys = message.account_keys.clone();
759 message.instructions[0].accounts.pop();
760 assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err());
761 }
762
763 #[test]
764 fn test_parse_vote_state_update_switch_ix() {
765 let vote_state_update = VoteStateUpdate::from(vec![(0, 3), (1, 2), (2, 1)]);
766
767 let vote_pubkey = Pubkey::new_unique();
768 let authorized_voter_pubkey = Pubkey::new_unique();
769 let proof_hash = Hash::new_from_array([2; 32]);
770 let instruction = vote_instruction::update_vote_state_switch(
771 &vote_pubkey,
772 &authorized_voter_pubkey,
773 vote_state_update.clone(),
774 proof_hash,
775 );
776 let mut message = Message::new(&[instruction], None);
777 assert_eq!(
778 parse_vote(
779 &message.instructions[0],
780 &AccountKeys::new(&message.account_keys, None)
781 )
782 .unwrap(),
783 ParsedInstructionEnum {
784 instruction_type: "updatevotestateswitch".to_string(),
785 info: json!({
786 "voteAccount": vote_pubkey.to_string(),
787 "voteAuthority": authorized_voter_pubkey.to_string(),
788 "voteStateUpdate": {
789 "lockouts": vote_state_update.lockouts,
790 "root": None::<u64>,
791 "hash": Hash::default().to_string(),
792 "timestamp": None::<u64>,
793 },
794 "hash": proof_hash.to_string(),
795 }),
796 }
797 );
798 assert!(parse_vote(
799 &message.instructions[0],
800 &AccountKeys::new(&message.account_keys[0..1], None)
801 )
802 .is_err());
803 let keys = message.account_keys.clone();
804 message.instructions[0].accounts.pop();
805 assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err());
806 }
807
808 #[test]
809 fn test_parse_compact_vote_state_update_ix() {
810 let vote_state_update = VoteStateUpdate::from(vec![(0, 3), (1, 2), (2, 1)]);
811 let compact_vote_state_update = vote_state_update.clone();
812
813 let vote_pubkey = Pubkey::new_unique();
814 let authorized_voter_pubkey = Pubkey::new_unique();
815 let instruction = vote_instruction::compact_update_vote_state(
816 &vote_pubkey,
817 &authorized_voter_pubkey,
818 compact_vote_state_update,
819 );
820 let mut message = Message::new(&[instruction], None);
821 assert_eq!(
822 parse_vote(
823 &message.instructions[0],
824 &AccountKeys::new(&message.account_keys, None)
825 )
826 .unwrap(),
827 ParsedInstructionEnum {
828 instruction_type: "compactupdatevotestate".to_string(),
829 info: json!({
830 "voteAccount": vote_pubkey.to_string(),
831 "voteAuthority": authorized_voter_pubkey.to_string(),
832 "voteStateUpdate": {
833 "lockouts": vote_state_update.lockouts,
834 "root": None::<u64>,
835 "hash": Hash::default().to_string(),
836 "timestamp": None::<u64>,
837 },
838 }),
839 }
840 );
841 assert!(parse_vote(
842 &message.instructions[0],
843 &AccountKeys::new(&message.account_keys[0..1], None)
844 )
845 .is_err());
846 let keys = message.account_keys.clone();
847 message.instructions[0].accounts.pop();
848 assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err());
849 }
850
851 #[test]
852 fn test_parse_compact_vote_state_update_switch_ix() {
853 let vote_state_update = VoteStateUpdate::from(vec![(0, 3), (1, 2), (2, 1)]);
854 let compact_vote_state_update = vote_state_update.clone();
855
856 let vote_pubkey = Pubkey::new_unique();
857 let authorized_voter_pubkey = Pubkey::new_unique();
858 let proof_hash = Hash::new_from_array([2; 32]);
859 let instruction = vote_instruction::compact_update_vote_state_switch(
860 &vote_pubkey,
861 &authorized_voter_pubkey,
862 compact_vote_state_update,
863 proof_hash,
864 );
865 let mut message = Message::new(&[instruction], None);
866 assert_eq!(
867 parse_vote(
868 &message.instructions[0],
869 &AccountKeys::new(&message.account_keys, None)
870 )
871 .unwrap(),
872 ParsedInstructionEnum {
873 instruction_type: "compactupdatevotestateswitch".to_string(),
874 info: json!({
875 "voteAccount": vote_pubkey.to_string(),
876 "voteAuthority": authorized_voter_pubkey.to_string(),
877 "voteStateUpdate": {
878 "lockouts": vote_state_update.lockouts,
879 "root": None::<u64>,
880 "hash": Hash::default().to_string(),
881 "timestamp": None::<u64>,
882 },
883 "hash": proof_hash.to_string(),
884 }),
885 }
886 );
887 assert!(parse_vote(
888 &message.instructions[0],
889 &AccountKeys::new(&message.account_keys[0..1], None)
890 )
891 .is_err());
892 let keys = message.account_keys.clone();
893 message.instructions[0].accounts.pop();
894 assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err());
895 }
896
897 #[test]
898 fn test_parse_tower_sync_ix() {
899 let tower_sync = TowerSync::from(vec![(0, 3), (1, 2), (2, 1)]);
900
901 let vote_pubkey = Pubkey::new_unique();
902 let authorized_voter_pubkey = Pubkey::new_unique();
903 let instruction = vote_instruction::tower_sync(
904 &vote_pubkey,
905 &authorized_voter_pubkey,
906 tower_sync.clone(),
907 );
908 let mut message = Message::new(&[instruction], None);
909 assert_eq!(
910 parse_vote(
911 &message.instructions[0],
912 &AccountKeys::new(&message.account_keys, None)
913 )
914 .unwrap(),
915 ParsedInstructionEnum {
916 instruction_type: "towersync".to_string(),
917 info: json!({
918 "voteAccount": vote_pubkey.to_string(),
919 "voteAuthority": authorized_voter_pubkey.to_string(),
920 "towerSync": {
921 "lockouts": tower_sync.lockouts,
922 "root": None::<u64>,
923 "hash": Hash::default().to_string(),
924 "timestamp": None::<u64>,
925 "blockId": Hash::default().to_string(),
926 },
927 }),
928 }
929 );
930 assert!(parse_vote(
931 &message.instructions[0],
932 &AccountKeys::new(&message.account_keys[0..1], None)
933 )
934 .is_err());
935 let keys = message.account_keys.clone();
936 message.instructions[0].accounts.pop();
937 assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err());
938 }
939
940 #[test]
941 fn test_parse_tower_sync_switch_ix() {
942 let tower_sync = TowerSync::from(vec![(0, 3), (1, 2), (2, 1)]);
943
944 let vote_pubkey = Pubkey::new_unique();
945 let authorized_voter_pubkey = Pubkey::new_unique();
946 let proof_hash = Hash::new_from_array([2; 32]);
947 let instruction = vote_instruction::tower_sync_switch(
948 &vote_pubkey,
949 &authorized_voter_pubkey,
950 tower_sync.clone(),
951 proof_hash,
952 );
953 let mut message = Message::new(&[instruction], None);
954 assert_eq!(
955 parse_vote(
956 &message.instructions[0],
957 &AccountKeys::new(&message.account_keys, None)
958 )
959 .unwrap(),
960 ParsedInstructionEnum {
961 instruction_type: "towersyncswitch".to_string(),
962 info: json!({
963 "voteAccount": vote_pubkey.to_string(),
964 "voteAuthority": authorized_voter_pubkey.to_string(),
965 "towerSync": {
966 "lockouts": tower_sync.lockouts,
967 "root": None::<u64>,
968 "hash": Hash::default().to_string(),
969 "timestamp": None::<u64>,
970 "blockId": Hash::default().to_string(),
971 },
972 "hash": proof_hash.to_string(),
973 }),
974 }
975 );
976 assert!(parse_vote(
977 &message.instructions[0],
978 &AccountKeys::new(&message.account_keys[0..1], None)
979 )
980 .is_err());
981 let keys = message.account_keys.clone();
982 message.instructions[0].accounts.pop();
983 assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err());
984 }
985}