miraland_program/vote/
instruction.rs

1//! Vote program instructions
2
3use {
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    /// Initialize a vote account
25    ///
26    /// # Account references
27    ///   0. `[WRITE]` Uninitialized vote account
28    ///   1. `[]` Rent sysvar
29    ///   2. `[]` Clock sysvar
30    ///   3. `[SIGNER]` New validator identity (node_pubkey)
31    InitializeAccount(VoteInit),
32
33    /// Authorize a key to send votes or issue a withdrawal
34    ///
35    /// # Account references
36    ///   0. `[WRITE]` Vote account to be updated with the Pubkey for authorization
37    ///   1. `[]` Clock sysvar
38    ///   2. `[SIGNER]` Vote or withdraw authority
39    Authorize(Pubkey, VoteAuthorize),
40
41    /// A Vote instruction with recent votes
42    ///
43    /// # Account references
44    ///   0. `[WRITE]` Vote account to vote with
45    ///   1. `[]` Slot hashes sysvar
46    ///   2. `[]` Clock sysvar
47    ///   3. `[SIGNER]` Vote authority
48    Vote(Vote),
49
50    /// Withdraw some amount of funds
51    ///
52    /// # Account references
53    ///   0. `[WRITE]` Vote account to withdraw from
54    ///   1. `[WRITE]` Recipient account
55    ///   2. `[SIGNER]` Withdraw authority
56    Withdraw(u64),
57
58    /// Update the vote account's validator identity (node_pubkey)
59    ///
60    /// # Account references
61    ///   0. `[WRITE]` Vote account to be updated with the given authority public key
62    ///   1. `[SIGNER]` New validator identity (node_pubkey)
63    ///   2. `[SIGNER]` Withdraw authority
64    UpdateValidatorIdentity,
65
66    /// Update the commission for the vote account
67    ///
68    /// # Account references
69    ///   0. `[WRITE]` Vote account to be updated
70    ///   1. `[SIGNER]` Withdraw authority
71    UpdateCommission(u8),
72
73    /// A Vote instruction with recent votes
74    ///
75    /// # Account references
76    ///   0. `[WRITE]` Vote account to vote with
77    ///   1. `[]` Slot hashes sysvar
78    ///   2. `[]` Clock sysvar
79    ///   3. `[SIGNER]` Vote authority
80    VoteSwitch(Vote, Hash),
81
82    /// Authorize a key to send votes or issue a withdrawal
83    ///
84    /// This instruction behaves like `Authorize` with the additional requirement that the new vote
85    /// or withdraw authority must also be a signer.
86    ///
87    /// # Account references
88    ///   0. `[WRITE]` Vote account to be updated with the Pubkey for authorization
89    ///   1. `[]` Clock sysvar
90    ///   2. `[SIGNER]` Vote or withdraw authority
91    ///   3. `[SIGNER]` New vote or withdraw authority
92    AuthorizeChecked(VoteAuthorize),
93
94    /// Update the onchain vote state for the signer.
95    ///
96    /// # Account references
97    ///   0. `[Write]` Vote account to vote with
98    ///   1. `[SIGNER]` Vote authority
99    UpdateVoteState(VoteStateUpdate),
100
101    /// Update the onchain vote state for the signer along with a switching proof.
102    ///
103    /// # Account references
104    ///   0. `[Write]` Vote account to vote with
105    ///   1. `[SIGNER]` Vote authority
106    UpdateVoteStateSwitch(VoteStateUpdate, Hash),
107
108    /// Given that the current Voter or Withdrawer authority is a derived key,
109    /// this instruction allows someone who can sign for that derived key's
110    /// base key to authorize a new Voter or Withdrawer for a vote account.
111    ///
112    /// # Account references
113    ///   0. `[Write]` Vote account to be updated
114    ///   1. `[]` Clock sysvar
115    ///   2. `[SIGNER]` Base key of current Voter or Withdrawer authority's derived key
116    AuthorizeWithSeed(VoteAuthorizeWithSeedArgs),
117
118    /// Given that the current Voter or Withdrawer authority is a derived key,
119    /// this instruction allows someone who can sign for that derived key's
120    /// base key to authorize a new Voter or Withdrawer for a vote account.
121    ///
122    /// This instruction behaves like `AuthorizeWithSeed` with the additional requirement
123    /// that the new vote or withdraw authority must also be a signer.
124    ///
125    /// # Account references
126    ///   0. `[Write]` Vote account to be updated
127    ///   1. `[]` Clock sysvar
128    ///   2. `[SIGNER]` Base key of current Voter or Withdrawer authority's derived key
129    ///   3. `[SIGNER]` New vote or withdraw authority
130    AuthorizeCheckedWithSeed(VoteAuthorizeCheckedWithSeedArgs),
131
132    /// Update the onchain vote state for the signer.
133    ///
134    /// # Account references
135    ///   0. `[Write]` Vote account to vote with
136    ///   1. `[SIGNER]` Vote authority
137    #[serde(with = "serde_compact_vote_state_update")]
138    CompactUpdateVoteState(VoteStateUpdate),
139
140    /// Update the onchain vote state for the signer along with a switching proof.
141    ///
142    /// # Account references
143    ///   0. `[Write]` Vote account to vote with
144    ///   1. `[SIGNER]` Vote authority
145    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    /// Only to be used on vote instructions (guard with is_simple_vote),  panics otherwise
175    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    /// Only to be used on vote instructions (guard with is_simple_vote),  panics otherwise
190    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, // currently authorized
293    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, // currently authorized
312    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}