1use {
4 super::state::TowerSync,
5 crate::state::{
6 Vote, VoteAuthorize, VoteAuthorizeCheckedWithSeedArgs, VoteAuthorizeWithSeedArgs, VoteInit,
7 VoteStateUpdate, VoteStateVersions,
8 },
9 solana_clock::{Slot, UnixTimestamp},
10 solana_hash::Hash,
11 solana_pubkey::Pubkey,
12};
13#[cfg(feature = "bincode")]
14use {
15 crate::program::id,
16 solana_instruction::{AccountMeta, Instruction},
17 solana_sdk_ids::sysvar,
18};
19#[cfg(feature = "serde")]
20use {
21 crate::state::{serde_compact_vote_state_update, serde_tower_sync},
22 serde_derive::{Deserialize, Serialize},
23};
24
25#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
26#[derive(Debug, PartialEq, Eq, Clone)]
27pub enum VoteInstruction {
28 InitializeAccount(VoteInit),
36
37 Authorize(Pubkey, VoteAuthorize),
44
45 Vote(Vote),
53
54 Withdraw(u64),
61
62 UpdateValidatorIdentity,
69
70 UpdateCommission(u8),
76
77 VoteSwitch(Vote, Hash),
85
86 AuthorizeChecked(VoteAuthorize),
97
98 UpdateVoteState(VoteStateUpdate),
104
105 UpdateVoteStateSwitch(VoteStateUpdate, Hash),
111
112 AuthorizeWithSeed(VoteAuthorizeWithSeedArgs),
121
122 AuthorizeCheckedWithSeed(VoteAuthorizeCheckedWithSeedArgs),
135
136 #[cfg_attr(feature = "serde", serde(with = "serde_compact_vote_state_update"))]
142 CompactUpdateVoteState(VoteStateUpdate),
143
144 CompactUpdateVoteStateSwitch(
150 #[cfg_attr(feature = "serde", serde(with = "serde_compact_vote_state_update"))]
151 VoteStateUpdate,
152 Hash,
153 ),
154
155 #[cfg_attr(feature = "serde", serde(with = "serde_tower_sync"))]
161 TowerSync(TowerSync),
162
163 TowerSyncSwitch(
169 #[cfg_attr(feature = "serde", serde(with = "serde_tower_sync"))] TowerSync,
170 Hash,
171 ),
172}
173
174impl VoteInstruction {
175 pub fn is_simple_vote(&self) -> bool {
176 matches!(
177 self,
178 Self::Vote(_)
179 | Self::VoteSwitch(_, _)
180 | Self::UpdateVoteState(_)
181 | Self::UpdateVoteStateSwitch(_, _)
182 | Self::CompactUpdateVoteState(_)
183 | Self::CompactUpdateVoteStateSwitch(_, _)
184 | Self::TowerSync(_)
185 | Self::TowerSyncSwitch(_, _),
186 )
187 }
188
189 pub fn is_single_vote_state_update(&self) -> bool {
190 matches!(
191 self,
192 Self::UpdateVoteState(_)
193 | Self::UpdateVoteStateSwitch(_, _)
194 | Self::CompactUpdateVoteState(_)
195 | Self::CompactUpdateVoteStateSwitch(_, _)
196 | Self::TowerSync(_)
197 | Self::TowerSyncSwitch(_, _),
198 )
199 }
200
201 pub fn last_voted_slot(&self) -> Option<Slot> {
203 assert!(self.is_simple_vote());
204 match self {
205 Self::Vote(v) | Self::VoteSwitch(v, _) => v.last_voted_slot(),
206 Self::UpdateVoteState(vote_state_update)
207 | Self::UpdateVoteStateSwitch(vote_state_update, _)
208 | Self::CompactUpdateVoteState(vote_state_update)
209 | Self::CompactUpdateVoteStateSwitch(vote_state_update, _) => {
210 vote_state_update.last_voted_slot()
211 }
212 Self::TowerSync(tower_sync) | Self::TowerSyncSwitch(tower_sync, _) => {
213 tower_sync.last_voted_slot()
214 }
215 _ => panic!("Tried to get slot on non simple vote instruction"),
216 }
217 }
218
219 pub fn hash(&self) -> Hash {
221 assert!(self.is_simple_vote());
222 match self {
223 Self::Vote(v) | Self::VoteSwitch(v, _) => v.hash,
224 Self::UpdateVoteState(vote_state_update)
225 | Self::UpdateVoteStateSwitch(vote_state_update, _)
226 | Self::CompactUpdateVoteState(vote_state_update)
227 | Self::CompactUpdateVoteStateSwitch(vote_state_update, _) => vote_state_update.hash,
228 Self::TowerSync(tower_sync) | Self::TowerSyncSwitch(tower_sync, _) => tower_sync.hash,
229 _ => panic!("Tried to get hash on non simple vote instruction"),
230 }
231 }
232 pub fn timestamp(&self) -> Option<UnixTimestamp> {
234 assert!(self.is_simple_vote());
235 match self {
236 Self::Vote(v) | Self::VoteSwitch(v, _) => v.timestamp,
237 Self::UpdateVoteState(vote_state_update)
238 | Self::UpdateVoteStateSwitch(vote_state_update, _)
239 | Self::CompactUpdateVoteState(vote_state_update)
240 | Self::CompactUpdateVoteStateSwitch(vote_state_update, _) => {
241 vote_state_update.timestamp
242 }
243 Self::TowerSync(tower_sync) | Self::TowerSyncSwitch(tower_sync, _) => {
244 tower_sync.timestamp
245 }
246 _ => panic!("Tried to get timestamp on non simple vote instruction"),
247 }
248 }
249}
250
251#[cfg(feature = "bincode")]
252fn initialize_account(vote_pubkey: &Pubkey, vote_init: &VoteInit) -> Instruction {
253 let account_metas = vec![
254 AccountMeta::new(*vote_pubkey, false),
255 AccountMeta::new_readonly(sysvar::rent::id(), false),
256 AccountMeta::new_readonly(sysvar::clock::id(), false),
257 AccountMeta::new_readonly(vote_init.node_pubkey, true),
258 ];
259
260 Instruction::new_with_bincode(
261 id(),
262 &VoteInstruction::InitializeAccount(*vote_init),
263 account_metas,
264 )
265}
266
267pub struct CreateVoteAccountConfig<'a> {
268 pub space: u64,
269 pub with_seed: Option<(&'a Pubkey, &'a str)>,
270}
271
272impl Default for CreateVoteAccountConfig<'_> {
273 fn default() -> Self {
274 Self {
275 space: VoteStateVersions::vote_state_size_of(false) as u64,
276 with_seed: None,
277 }
278 }
279}
280
281#[cfg(feature = "bincode")]
282pub fn create_account_with_config(
283 from_pubkey: &Pubkey,
284 vote_pubkey: &Pubkey,
285 vote_init: &VoteInit,
286 lamports: u64,
287 config: CreateVoteAccountConfig,
288) -> Vec<Instruction> {
289 let create_ix = if let Some((base, seed)) = config.with_seed {
290 solana_system_interface::instruction::create_account_with_seed(
291 from_pubkey,
292 vote_pubkey,
293 base,
294 seed,
295 lamports,
296 config.space,
297 &id(),
298 )
299 } else {
300 solana_system_interface::instruction::create_account(
301 from_pubkey,
302 vote_pubkey,
303 lamports,
304 config.space,
305 &id(),
306 )
307 };
308 let init_ix = initialize_account(vote_pubkey, vote_init);
309 vec![create_ix, init_ix]
310}
311
312#[cfg(feature = "bincode")]
313pub fn authorize(
314 vote_pubkey: &Pubkey,
315 authorized_pubkey: &Pubkey, new_authorized_pubkey: &Pubkey,
317 vote_authorize: VoteAuthorize,
318) -> Instruction {
319 let account_metas = vec![
320 AccountMeta::new(*vote_pubkey, false),
321 AccountMeta::new_readonly(sysvar::clock::id(), false),
322 AccountMeta::new_readonly(*authorized_pubkey, true),
323 ];
324
325 Instruction::new_with_bincode(
326 id(),
327 &VoteInstruction::Authorize(*new_authorized_pubkey, vote_authorize),
328 account_metas,
329 )
330}
331
332#[cfg(feature = "bincode")]
333pub fn authorize_checked(
334 vote_pubkey: &Pubkey,
335 authorized_pubkey: &Pubkey, new_authorized_pubkey: &Pubkey,
337 vote_authorize: VoteAuthorize,
338) -> Instruction {
339 let account_metas = vec![
340 AccountMeta::new(*vote_pubkey, false),
341 AccountMeta::new_readonly(sysvar::clock::id(), false),
342 AccountMeta::new_readonly(*authorized_pubkey, true),
343 AccountMeta::new_readonly(*new_authorized_pubkey, true),
344 ];
345
346 Instruction::new_with_bincode(
347 id(),
348 &VoteInstruction::AuthorizeChecked(vote_authorize),
349 account_metas,
350 )
351}
352
353#[cfg(feature = "bincode")]
354pub fn authorize_with_seed(
355 vote_pubkey: &Pubkey,
356 current_authority_base_key: &Pubkey,
357 current_authority_derived_key_owner: &Pubkey,
358 current_authority_derived_key_seed: &str,
359 new_authority: &Pubkey,
360 authorization_type: VoteAuthorize,
361) -> Instruction {
362 let account_metas = vec![
363 AccountMeta::new(*vote_pubkey, false),
364 AccountMeta::new_readonly(sysvar::clock::id(), false),
365 AccountMeta::new_readonly(*current_authority_base_key, true),
366 ];
367
368 Instruction::new_with_bincode(
369 id(),
370 &VoteInstruction::AuthorizeWithSeed(VoteAuthorizeWithSeedArgs {
371 authorization_type,
372 current_authority_derived_key_owner: *current_authority_derived_key_owner,
373 current_authority_derived_key_seed: current_authority_derived_key_seed.to_string(),
374 new_authority: *new_authority,
375 }),
376 account_metas,
377 )
378}
379
380#[cfg(feature = "bincode")]
381pub fn authorize_checked_with_seed(
382 vote_pubkey: &Pubkey,
383 current_authority_base_key: &Pubkey,
384 current_authority_derived_key_owner: &Pubkey,
385 current_authority_derived_key_seed: &str,
386 new_authority: &Pubkey,
387 authorization_type: VoteAuthorize,
388) -> Instruction {
389 let account_metas = vec![
390 AccountMeta::new(*vote_pubkey, false),
391 AccountMeta::new_readonly(sysvar::clock::id(), false),
392 AccountMeta::new_readonly(*current_authority_base_key, true),
393 AccountMeta::new_readonly(*new_authority, true),
394 ];
395
396 Instruction::new_with_bincode(
397 id(),
398 &VoteInstruction::AuthorizeCheckedWithSeed(VoteAuthorizeCheckedWithSeedArgs {
399 authorization_type,
400 current_authority_derived_key_owner: *current_authority_derived_key_owner,
401 current_authority_derived_key_seed: current_authority_derived_key_seed.to_string(),
402 }),
403 account_metas,
404 )
405}
406
407#[cfg(feature = "bincode")]
408pub fn update_validator_identity(
409 vote_pubkey: &Pubkey,
410 authorized_withdrawer_pubkey: &Pubkey,
411 node_pubkey: &Pubkey,
412) -> Instruction {
413 let account_metas = vec![
414 AccountMeta::new(*vote_pubkey, false),
415 AccountMeta::new_readonly(*node_pubkey, true),
416 AccountMeta::new_readonly(*authorized_withdrawer_pubkey, true),
417 ];
418
419 Instruction::new_with_bincode(
420 id(),
421 &VoteInstruction::UpdateValidatorIdentity,
422 account_metas,
423 )
424}
425
426#[cfg(feature = "bincode")]
427pub fn update_commission(
428 vote_pubkey: &Pubkey,
429 authorized_withdrawer_pubkey: &Pubkey,
430 commission: u8,
431) -> Instruction {
432 let account_metas = vec![
433 AccountMeta::new(*vote_pubkey, false),
434 AccountMeta::new_readonly(*authorized_withdrawer_pubkey, true),
435 ];
436
437 Instruction::new_with_bincode(
438 id(),
439 &VoteInstruction::UpdateCommission(commission),
440 account_metas,
441 )
442}
443
444#[cfg(feature = "bincode")]
445pub fn vote(vote_pubkey: &Pubkey, authorized_voter_pubkey: &Pubkey, vote: Vote) -> Instruction {
446 let account_metas = vec![
447 AccountMeta::new(*vote_pubkey, false),
448 AccountMeta::new_readonly(sysvar::slot_hashes::id(), false),
449 AccountMeta::new_readonly(sysvar::clock::id(), false),
450 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
451 ];
452
453 Instruction::new_with_bincode(id(), &VoteInstruction::Vote(vote), account_metas)
454}
455
456#[cfg(feature = "bincode")]
457pub fn vote_switch(
458 vote_pubkey: &Pubkey,
459 authorized_voter_pubkey: &Pubkey,
460 vote: Vote,
461 proof_hash: Hash,
462) -> Instruction {
463 let account_metas = vec![
464 AccountMeta::new(*vote_pubkey, false),
465 AccountMeta::new_readonly(sysvar::slot_hashes::id(), false),
466 AccountMeta::new_readonly(sysvar::clock::id(), false),
467 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
468 ];
469
470 Instruction::new_with_bincode(
471 id(),
472 &VoteInstruction::VoteSwitch(vote, proof_hash),
473 account_metas,
474 )
475}
476
477#[cfg(feature = "bincode")]
478pub fn update_vote_state(
479 vote_pubkey: &Pubkey,
480 authorized_voter_pubkey: &Pubkey,
481 vote_state_update: VoteStateUpdate,
482) -> Instruction {
483 let account_metas = vec![
484 AccountMeta::new(*vote_pubkey, false),
485 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
486 ];
487
488 Instruction::new_with_bincode(
489 id(),
490 &VoteInstruction::UpdateVoteState(vote_state_update),
491 account_metas,
492 )
493}
494
495#[cfg(feature = "bincode")]
496pub fn update_vote_state_switch(
497 vote_pubkey: &Pubkey,
498 authorized_voter_pubkey: &Pubkey,
499 vote_state_update: VoteStateUpdate,
500 proof_hash: Hash,
501) -> Instruction {
502 let account_metas = vec![
503 AccountMeta::new(*vote_pubkey, false),
504 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
505 ];
506
507 Instruction::new_with_bincode(
508 id(),
509 &VoteInstruction::UpdateVoteStateSwitch(vote_state_update, proof_hash),
510 account_metas,
511 )
512}
513
514#[cfg(feature = "bincode")]
515pub fn compact_update_vote_state(
516 vote_pubkey: &Pubkey,
517 authorized_voter_pubkey: &Pubkey,
518 vote_state_update: VoteStateUpdate,
519) -> Instruction {
520 let account_metas = vec![
521 AccountMeta::new(*vote_pubkey, false),
522 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
523 ];
524
525 Instruction::new_with_bincode(
526 id(),
527 &VoteInstruction::CompactUpdateVoteState(vote_state_update),
528 account_metas,
529 )
530}
531
532#[cfg(feature = "bincode")]
533pub fn compact_update_vote_state_switch(
534 vote_pubkey: &Pubkey,
535 authorized_voter_pubkey: &Pubkey,
536 vote_state_update: VoteStateUpdate,
537 proof_hash: Hash,
538) -> Instruction {
539 let account_metas = vec![
540 AccountMeta::new(*vote_pubkey, false),
541 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
542 ];
543
544 Instruction::new_with_bincode(
545 id(),
546 &VoteInstruction::CompactUpdateVoteStateSwitch(vote_state_update, proof_hash),
547 account_metas,
548 )
549}
550
551#[cfg(feature = "bincode")]
552pub fn tower_sync(
553 vote_pubkey: &Pubkey,
554 authorized_voter_pubkey: &Pubkey,
555 tower_sync: TowerSync,
556) -> Instruction {
557 let account_metas = vec![
558 AccountMeta::new(*vote_pubkey, false),
559 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
560 ];
561
562 Instruction::new_with_bincode(id(), &VoteInstruction::TowerSync(tower_sync), account_metas)
563}
564
565#[cfg(feature = "bincode")]
566pub fn tower_sync_switch(
567 vote_pubkey: &Pubkey,
568 authorized_voter_pubkey: &Pubkey,
569 tower_sync: TowerSync,
570 proof_hash: Hash,
571) -> Instruction {
572 let account_metas = vec![
573 AccountMeta::new(*vote_pubkey, false),
574 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
575 ];
576
577 Instruction::new_with_bincode(
578 id(),
579 &VoteInstruction::TowerSyncSwitch(tower_sync, proof_hash),
580 account_metas,
581 )
582}
583
584#[cfg(feature = "bincode")]
585pub fn withdraw(
586 vote_pubkey: &Pubkey,
587 authorized_withdrawer_pubkey: &Pubkey,
588 lamports: u64,
589 to_pubkey: &Pubkey,
590) -> Instruction {
591 let account_metas = vec![
592 AccountMeta::new(*vote_pubkey, false),
593 AccountMeta::new(*to_pubkey, false),
594 AccountMeta::new_readonly(*authorized_withdrawer_pubkey, true),
595 ];
596
597 Instruction::new_with_bincode(id(), &VoteInstruction::Withdraw(lamports), account_metas)
598}