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