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