1use {
4 super::state::TowerSync,
5 crate::{
6 hash::Hash,
7 instruction::{AccountMeta, Instruction},
8 pubkey::Pubkey,
9 system_instruction, sysvar,
10 vote::{
11 program::id,
12 state::{
13 serde_compact_vote_state_update, serde_tower_sync, Vote, VoteAuthorize,
14 VoteAuthorizeCheckedWithSeedArgs, VoteAuthorizeWithSeedArgs, VoteInit,
15 VoteStateUpdate, VoteStateVersions,
16 },
17 },
18 },
19 serde_derive::{Deserialize, Serialize},
20 solana_clock::{Slot, UnixTimestamp},
21};
22
23#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
24pub enum VoteInstruction {
25 InitializeAccount(VoteInit),
33
34 Authorize(Pubkey, VoteAuthorize),
41
42 Vote(Vote),
50
51 Withdraw(u64),
58
59 UpdateValidatorIdentity,
66
67 UpdateCommission(u8),
73
74 VoteSwitch(Vote, Hash),
82
83 AuthorizeChecked(VoteAuthorize),
94
95 UpdateVoteState(VoteStateUpdate),
101
102 UpdateVoteStateSwitch(VoteStateUpdate, Hash),
108
109 AuthorizeWithSeed(VoteAuthorizeWithSeedArgs),
118
119 AuthorizeCheckedWithSeed(VoteAuthorizeCheckedWithSeedArgs),
132
133 #[serde(with = "serde_compact_vote_state_update")]
139 CompactUpdateVoteState(VoteStateUpdate),
140
141 CompactUpdateVoteStateSwitch(
147 #[serde(with = "serde_compact_vote_state_update")] VoteStateUpdate,
148 Hash,
149 ),
150
151 #[serde(with = "serde_tower_sync")]
157 TowerSync(TowerSync),
158
159 TowerSyncSwitch(#[serde(with = "serde_tower_sync")] TowerSync, Hash),
165}
166
167impl VoteInstruction {
168 pub fn is_simple_vote(&self) -> bool {
169 matches!(
170 self,
171 Self::Vote(_)
172 | Self::VoteSwitch(_, _)
173 | Self::UpdateVoteState(_)
174 | Self::UpdateVoteStateSwitch(_, _)
175 | Self::CompactUpdateVoteState(_)
176 | Self::CompactUpdateVoteStateSwitch(_, _)
177 | Self::TowerSync(_)
178 | Self::TowerSyncSwitch(_, _),
179 )
180 }
181
182 pub fn is_single_vote_state_update(&self) -> bool {
183 matches!(
184 self,
185 Self::UpdateVoteState(_)
186 | Self::UpdateVoteStateSwitch(_, _)
187 | Self::CompactUpdateVoteState(_)
188 | Self::CompactUpdateVoteStateSwitch(_, _)
189 | Self::TowerSync(_)
190 | Self::TowerSyncSwitch(_, _),
191 )
192 }
193
194 pub fn last_voted_slot(&self) -> Option<Slot> {
196 assert!(self.is_simple_vote());
197 match self {
198 Self::Vote(v) | Self::VoteSwitch(v, _) => v.last_voted_slot(),
199 Self::UpdateVoteState(vote_state_update)
200 | Self::UpdateVoteStateSwitch(vote_state_update, _)
201 | Self::CompactUpdateVoteState(vote_state_update)
202 | Self::CompactUpdateVoteStateSwitch(vote_state_update, _) => {
203 vote_state_update.last_voted_slot()
204 }
205 Self::TowerSync(tower_sync) | Self::TowerSyncSwitch(tower_sync, _) => {
206 tower_sync.last_voted_slot()
207 }
208 _ => panic!("Tried to get slot on non simple vote instruction"),
209 }
210 }
211
212 pub fn hash(&self) -> Hash {
214 assert!(self.is_simple_vote());
215 match self {
216 Self::Vote(v) | Self::VoteSwitch(v, _) => v.hash,
217 Self::UpdateVoteState(vote_state_update)
218 | Self::UpdateVoteStateSwitch(vote_state_update, _)
219 | Self::CompactUpdateVoteState(vote_state_update)
220 | Self::CompactUpdateVoteStateSwitch(vote_state_update, _) => vote_state_update.hash,
221 Self::TowerSync(tower_sync) | Self::TowerSyncSwitch(tower_sync, _) => tower_sync.hash,
222 _ => panic!("Tried to get hash on non simple vote instruction"),
223 }
224 }
225 pub fn timestamp(&self) -> Option<UnixTimestamp> {
227 assert!(self.is_simple_vote());
228 match self {
229 Self::Vote(v) | Self::VoteSwitch(v, _) => v.timestamp,
230 Self::UpdateVoteState(vote_state_update)
231 | Self::UpdateVoteStateSwitch(vote_state_update, _)
232 | Self::CompactUpdateVoteState(vote_state_update)
233 | Self::CompactUpdateVoteStateSwitch(vote_state_update, _) => {
234 vote_state_update.timestamp
235 }
236 Self::TowerSync(tower_sync) | Self::TowerSyncSwitch(tower_sync, _) => {
237 tower_sync.timestamp
238 }
239 _ => panic!("Tried to get timestamp on non simple vote instruction"),
240 }
241 }
242}
243
244fn initialize_account(vote_pubkey: &Pubkey, vote_init: &VoteInit) -> Instruction {
245 let account_metas = vec![
246 AccountMeta::new(*vote_pubkey, false),
247 AccountMeta::new_readonly(sysvar::rent::id(), false),
248 AccountMeta::new_readonly(sysvar::clock::id(), false),
249 AccountMeta::new_readonly(vote_init.node_pubkey, true),
250 ];
251
252 Instruction::new_with_bincode(
253 id(),
254 &VoteInstruction::InitializeAccount(*vote_init),
255 account_metas,
256 )
257}
258
259pub struct CreateVoteAccountConfig<'a> {
260 pub space: u64,
261 pub with_seed: Option<(&'a Pubkey, &'a str)>,
262}
263
264impl<'a> Default for CreateVoteAccountConfig<'a> {
265 fn default() -> Self {
266 Self {
267 space: VoteStateVersions::vote_state_size_of(false) as u64,
268 with_seed: None,
269 }
270 }
271}
272
273pub fn create_account_with_config(
274 from_pubkey: &Pubkey,
275 vote_pubkey: &Pubkey,
276 vote_init: &VoteInit,
277 lamports: u64,
278 config: CreateVoteAccountConfig,
279) -> Vec<Instruction> {
280 let create_ix =
281 system_instruction::create_account(from_pubkey, vote_pubkey, lamports, config.space, &id());
282 let init_ix = initialize_account(vote_pubkey, vote_init);
283 vec![create_ix, init_ix]
284}
285
286pub fn authorize(
287 vote_pubkey: &Pubkey,
288 authorized_pubkey: &Pubkey, new_authorized_pubkey: &Pubkey,
290 vote_authorize: VoteAuthorize,
291) -> Instruction {
292 let account_metas = vec![
293 AccountMeta::new(*vote_pubkey, false),
294 AccountMeta::new_readonly(sysvar::clock::id(), false),
295 AccountMeta::new_readonly(*authorized_pubkey, true),
296 ];
297
298 Instruction::new_with_bincode(
299 id(),
300 &VoteInstruction::Authorize(*new_authorized_pubkey, vote_authorize),
301 account_metas,
302 )
303}
304
305pub fn authorize_checked(
306 vote_pubkey: &Pubkey,
307 authorized_pubkey: &Pubkey, new_authorized_pubkey: &Pubkey,
309 vote_authorize: VoteAuthorize,
310) -> Instruction {
311 let account_metas = vec![
312 AccountMeta::new(*vote_pubkey, false),
313 AccountMeta::new_readonly(sysvar::clock::id(), false),
314 AccountMeta::new_readonly(*authorized_pubkey, true),
315 AccountMeta::new_readonly(*new_authorized_pubkey, true),
316 ];
317
318 Instruction::new_with_bincode(
319 id(),
320 &VoteInstruction::AuthorizeChecked(vote_authorize),
321 account_metas,
322 )
323}
324
325pub fn authorize_with_seed(
326 vote_pubkey: &Pubkey,
327 current_authority_base_key: &Pubkey,
328 current_authority_derived_key_owner: &Pubkey,
329 current_authority_derived_key_seed: &str,
330 new_authority: &Pubkey,
331 authorization_type: VoteAuthorize,
332) -> Instruction {
333 let account_metas = vec![
334 AccountMeta::new(*vote_pubkey, false),
335 AccountMeta::new_readonly(sysvar::clock::id(), false),
336 AccountMeta::new_readonly(*current_authority_base_key, true),
337 ];
338
339 Instruction::new_with_bincode(
340 id(),
341 &VoteInstruction::AuthorizeWithSeed(VoteAuthorizeWithSeedArgs {
342 authorization_type,
343 current_authority_derived_key_owner: *current_authority_derived_key_owner,
344 current_authority_derived_key_seed: current_authority_derived_key_seed.to_string(),
345 new_authority: *new_authority,
346 }),
347 account_metas,
348 )
349}
350
351pub fn authorize_checked_with_seed(
352 vote_pubkey: &Pubkey,
353 current_authority_base_key: &Pubkey,
354 current_authority_derived_key_owner: &Pubkey,
355 current_authority_derived_key_seed: &str,
356 new_authority: &Pubkey,
357 authorization_type: VoteAuthorize,
358) -> Instruction {
359 let account_metas = vec![
360 AccountMeta::new(*vote_pubkey, false),
361 AccountMeta::new_readonly(sysvar::clock::id(), false),
362 AccountMeta::new_readonly(*current_authority_base_key, true),
363 AccountMeta::new_readonly(*new_authority, true),
364 ];
365
366 Instruction::new_with_bincode(
367 id(),
368 &VoteInstruction::AuthorizeCheckedWithSeed(VoteAuthorizeCheckedWithSeedArgs {
369 authorization_type,
370 current_authority_derived_key_owner: *current_authority_derived_key_owner,
371 current_authority_derived_key_seed: current_authority_derived_key_seed.to_string(),
372 }),
373 account_metas,
374 )
375}
376
377pub fn update_validator_identity(
378 vote_pubkey: &Pubkey,
379 authorized_withdrawer_pubkey: &Pubkey,
380 node_pubkey: &Pubkey,
381) -> Instruction {
382 let account_metas = vec![
383 AccountMeta::new(*vote_pubkey, false),
384 AccountMeta::new_readonly(*node_pubkey, true),
385 AccountMeta::new_readonly(*authorized_withdrawer_pubkey, true),
386 ];
387
388 Instruction::new_with_bincode(
389 id(),
390 &VoteInstruction::UpdateValidatorIdentity,
391 account_metas,
392 )
393}
394
395pub fn update_commission(
396 vote_pubkey: &Pubkey,
397 authorized_withdrawer_pubkey: &Pubkey,
398 commission: u8,
399) -> Instruction {
400 let account_metas = vec![
401 AccountMeta::new(*vote_pubkey, false),
402 AccountMeta::new_readonly(*authorized_withdrawer_pubkey, true),
403 ];
404
405 Instruction::new_with_bincode(
406 id(),
407 &VoteInstruction::UpdateCommission(commission),
408 account_metas,
409 )
410}
411
412pub fn vote(vote_pubkey: &Pubkey, authorized_voter_pubkey: &Pubkey, vote: Vote) -> Instruction {
413 let account_metas = vec![
414 AccountMeta::new(*vote_pubkey, false),
415 AccountMeta::new_readonly(sysvar::slot_hashes::id(), false),
416 AccountMeta::new_readonly(sysvar::clock::id(), false),
417 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
418 ];
419
420 Instruction::new_with_bincode(id(), &VoteInstruction::Vote(vote), account_metas)
421}
422
423pub fn vote_switch(
424 vote_pubkey: &Pubkey,
425 authorized_voter_pubkey: &Pubkey,
426 vote: Vote,
427 proof_hash: Hash,
428) -> Instruction {
429 let account_metas = vec![
430 AccountMeta::new(*vote_pubkey, false),
431 AccountMeta::new_readonly(sysvar::slot_hashes::id(), false),
432 AccountMeta::new_readonly(sysvar::clock::id(), false),
433 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
434 ];
435
436 Instruction::new_with_bincode(
437 id(),
438 &VoteInstruction::VoteSwitch(vote, proof_hash),
439 account_metas,
440 )
441}
442
443pub fn update_vote_state(
444 vote_pubkey: &Pubkey,
445 authorized_voter_pubkey: &Pubkey,
446 vote_state_update: VoteStateUpdate,
447) -> Instruction {
448 let account_metas = vec![
449 AccountMeta::new(*vote_pubkey, false),
450 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
451 ];
452
453 Instruction::new_with_bincode(
454 id(),
455 &VoteInstruction::UpdateVoteState(vote_state_update),
456 account_metas,
457 )
458}
459
460pub fn update_vote_state_switch(
461 vote_pubkey: &Pubkey,
462 authorized_voter_pubkey: &Pubkey,
463 vote_state_update: VoteStateUpdate,
464 proof_hash: Hash,
465) -> Instruction {
466 let account_metas = vec![
467 AccountMeta::new(*vote_pubkey, false),
468 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
469 ];
470
471 Instruction::new_with_bincode(
472 id(),
473 &VoteInstruction::UpdateVoteStateSwitch(vote_state_update, proof_hash),
474 account_metas,
475 )
476}
477
478pub fn compact_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::CompactUpdateVoteState(vote_state_update),
491 account_metas,
492 )
493}
494
495pub fn compact_update_vote_state_switch(
496 vote_pubkey: &Pubkey,
497 authorized_voter_pubkey: &Pubkey,
498 vote_state_update: VoteStateUpdate,
499 proof_hash: Hash,
500) -> Instruction {
501 let account_metas = vec![
502 AccountMeta::new(*vote_pubkey, false),
503 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
504 ];
505
506 Instruction::new_with_bincode(
507 id(),
508 &VoteInstruction::CompactUpdateVoteStateSwitch(vote_state_update, proof_hash),
509 account_metas,
510 )
511}
512
513pub fn tower_sync(
514 vote_pubkey: &Pubkey,
515 authorized_voter_pubkey: &Pubkey,
516 tower_sync: TowerSync,
517) -> Instruction {
518 let account_metas = vec![
519 AccountMeta::new(*vote_pubkey, false),
520 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
521 ];
522
523 Instruction::new_with_bincode(id(), &VoteInstruction::TowerSync(tower_sync), account_metas)
524}
525
526pub fn tower_sync_switch(
527 vote_pubkey: &Pubkey,
528 authorized_voter_pubkey: &Pubkey,
529 tower_sync: TowerSync,
530 proof_hash: Hash,
531) -> Instruction {
532 let account_metas = vec![
533 AccountMeta::new(*vote_pubkey, false),
534 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
535 ];
536
537 Instruction::new_with_bincode(
538 id(),
539 &VoteInstruction::TowerSyncSwitch(tower_sync, proof_hash),
540 account_metas,
541 )
542}
543
544pub fn withdraw(
545 vote_pubkey: &Pubkey,
546 authorized_withdrawer_pubkey: &Pubkey,
547 lamports: u64,
548 to_pubkey: &Pubkey,
549) -> Instruction {
550 let account_metas = vec![
551 AccountMeta::new(*vote_pubkey, false),
552 AccountMeta::new(*to_pubkey, false),
553 AccountMeta::new_readonly(*authorized_withdrawer_pubkey, true),
554 ];
555
556 Instruction::new_with_bincode(id(), &VoteInstruction::Withdraw(lamports), account_metas)
557}