cbe_program/vote/
instruction.rs

1//! Vote program instructions
2
3use {
4    crate::{
5        clock::Slot,
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, VoteState,
15                VoteStateUpdate,
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
190fn initialize_account(vote_pubkey: &Pubkey, vote_init: &VoteInit) -> Instruction {
191    let account_metas = vec![
192        AccountMeta::new(*vote_pubkey, false),
193        AccountMeta::new_readonly(sysvar::rent::id(), false),
194        AccountMeta::new_readonly(sysvar::clock::id(), false),
195        AccountMeta::new_readonly(vote_init.node_pubkey, true),
196    ];
197
198    Instruction::new_with_bincode(
199        id(),
200        &VoteInstruction::InitializeAccount(*vote_init),
201        account_metas,
202    )
203}
204
205pub fn create_account(
206    from_pubkey: &Pubkey,
207    vote_pubkey: &Pubkey,
208    vote_init: &VoteInit,
209    scoobies: u64,
210) -> Vec<Instruction> {
211    let space = VoteState::size_of() as u64;
212    let create_ix =
213        system_instruction::create_account(from_pubkey, vote_pubkey, scoobies, space, &id());
214    let init_ix = initialize_account(vote_pubkey, vote_init);
215    vec![create_ix, init_ix]
216}
217
218pub fn create_account_with_seed(
219    from_pubkey: &Pubkey,
220    vote_pubkey: &Pubkey,
221    base: &Pubkey,
222    seed: &str,
223    vote_init: &VoteInit,
224    scoobies: u64,
225) -> Vec<Instruction> {
226    let space = VoteState::size_of() as u64;
227    let create_ix = system_instruction::create_account_with_seed(
228        from_pubkey,
229        vote_pubkey,
230        base,
231        seed,
232        scoobies,
233        space,
234        &id(),
235    );
236    let init_ix = initialize_account(vote_pubkey, vote_init);
237    vec![create_ix, init_ix]
238}
239
240pub fn authorize(
241    vote_pubkey: &Pubkey,
242    authorized_pubkey: &Pubkey, // currently authorized
243    new_authorized_pubkey: &Pubkey,
244    vote_authorize: VoteAuthorize,
245) -> Instruction {
246    let account_metas = vec![
247        AccountMeta::new(*vote_pubkey, false),
248        AccountMeta::new_readonly(sysvar::clock::id(), false),
249        AccountMeta::new_readonly(*authorized_pubkey, true),
250    ];
251
252    Instruction::new_with_bincode(
253        id(),
254        &VoteInstruction::Authorize(*new_authorized_pubkey, vote_authorize),
255        account_metas,
256    )
257}
258
259pub fn authorize_checked(
260    vote_pubkey: &Pubkey,
261    authorized_pubkey: &Pubkey, // currently authorized
262    new_authorized_pubkey: &Pubkey,
263    vote_authorize: VoteAuthorize,
264) -> Instruction {
265    let account_metas = vec![
266        AccountMeta::new(*vote_pubkey, false),
267        AccountMeta::new_readonly(sysvar::clock::id(), false),
268        AccountMeta::new_readonly(*authorized_pubkey, true),
269        AccountMeta::new_readonly(*new_authorized_pubkey, true),
270    ];
271
272    Instruction::new_with_bincode(
273        id(),
274        &VoteInstruction::AuthorizeChecked(vote_authorize),
275        account_metas,
276    )
277}
278
279pub fn authorize_with_seed(
280    vote_pubkey: &Pubkey,
281    current_authority_base_key: &Pubkey,
282    current_authority_derived_key_owner: &Pubkey,
283    current_authority_derived_key_seed: &str,
284    new_authority: &Pubkey,
285    authorization_type: VoteAuthorize,
286) -> Instruction {
287    let account_metas = vec![
288        AccountMeta::new(*vote_pubkey, false),
289        AccountMeta::new_readonly(sysvar::clock::id(), false),
290        AccountMeta::new_readonly(*current_authority_base_key, true),
291    ];
292
293    Instruction::new_with_bincode(
294        id(),
295        &VoteInstruction::AuthorizeWithSeed(VoteAuthorizeWithSeedArgs {
296            authorization_type,
297            current_authority_derived_key_owner: *current_authority_derived_key_owner,
298            current_authority_derived_key_seed: current_authority_derived_key_seed.to_string(),
299            new_authority: *new_authority,
300        }),
301        account_metas,
302    )
303}
304
305pub fn authorize_checked_with_seed(
306    vote_pubkey: &Pubkey,
307    current_authority_base_key: &Pubkey,
308    current_authority_derived_key_owner: &Pubkey,
309    current_authority_derived_key_seed: &str,
310    new_authority: &Pubkey,
311    authorization_type: VoteAuthorize,
312) -> Instruction {
313    let account_metas = vec![
314        AccountMeta::new(*vote_pubkey, false),
315        AccountMeta::new_readonly(sysvar::clock::id(), false),
316        AccountMeta::new_readonly(*current_authority_base_key, true),
317        AccountMeta::new_readonly(*new_authority, true),
318    ];
319
320    Instruction::new_with_bincode(
321        id(),
322        &VoteInstruction::AuthorizeCheckedWithSeed(VoteAuthorizeCheckedWithSeedArgs {
323            authorization_type,
324            current_authority_derived_key_owner: *current_authority_derived_key_owner,
325            current_authority_derived_key_seed: current_authority_derived_key_seed.to_string(),
326        }),
327        account_metas,
328    )
329}
330
331pub fn update_validator_identity(
332    vote_pubkey: &Pubkey,
333    authorized_withdrawer_pubkey: &Pubkey,
334    node_pubkey: &Pubkey,
335) -> Instruction {
336    let account_metas = vec![
337        AccountMeta::new(*vote_pubkey, false),
338        AccountMeta::new_readonly(*node_pubkey, true),
339        AccountMeta::new_readonly(*authorized_withdrawer_pubkey, true),
340    ];
341
342    Instruction::new_with_bincode(
343        id(),
344        &VoteInstruction::UpdateValidatorIdentity,
345        account_metas,
346    )
347}
348
349pub fn update_commission(
350    vote_pubkey: &Pubkey,
351    authorized_withdrawer_pubkey: &Pubkey,
352    commission: u8,
353) -> Instruction {
354    let account_metas = vec![
355        AccountMeta::new(*vote_pubkey, false),
356        AccountMeta::new_readonly(*authorized_withdrawer_pubkey, true),
357    ];
358
359    Instruction::new_with_bincode(
360        id(),
361        &VoteInstruction::UpdateCommission(commission),
362        account_metas,
363    )
364}
365
366pub fn vote(vote_pubkey: &Pubkey, authorized_voter_pubkey: &Pubkey, vote: Vote) -> Instruction {
367    let account_metas = vec![
368        AccountMeta::new(*vote_pubkey, false),
369        AccountMeta::new_readonly(sysvar::slot_hashes::id(), false),
370        AccountMeta::new_readonly(sysvar::clock::id(), false),
371        AccountMeta::new_readonly(*authorized_voter_pubkey, true),
372    ];
373
374    Instruction::new_with_bincode(id(), &VoteInstruction::Vote(vote), account_metas)
375}
376
377pub fn vote_switch(
378    vote_pubkey: &Pubkey,
379    authorized_voter_pubkey: &Pubkey,
380    vote: Vote,
381    proof_hash: Hash,
382) -> Instruction {
383    let account_metas = vec![
384        AccountMeta::new(*vote_pubkey, false),
385        AccountMeta::new_readonly(sysvar::slot_hashes::id(), false),
386        AccountMeta::new_readonly(sysvar::clock::id(), false),
387        AccountMeta::new_readonly(*authorized_voter_pubkey, true),
388    ];
389
390    Instruction::new_with_bincode(
391        id(),
392        &VoteInstruction::VoteSwitch(vote, proof_hash),
393        account_metas,
394    )
395}
396
397pub fn update_vote_state(
398    vote_pubkey: &Pubkey,
399    authorized_voter_pubkey: &Pubkey,
400    vote_state_update: VoteStateUpdate,
401) -> Instruction {
402    let account_metas = vec![
403        AccountMeta::new(*vote_pubkey, false),
404        AccountMeta::new_readonly(*authorized_voter_pubkey, true),
405    ];
406
407    Instruction::new_with_bincode(
408        id(),
409        &VoteInstruction::UpdateVoteState(vote_state_update),
410        account_metas,
411    )
412}
413
414pub fn update_vote_state_switch(
415    vote_pubkey: &Pubkey,
416    authorized_voter_pubkey: &Pubkey,
417    vote_state_update: VoteStateUpdate,
418    proof_hash: Hash,
419) -> Instruction {
420    let account_metas = vec![
421        AccountMeta::new(*vote_pubkey, false),
422        AccountMeta::new_readonly(*authorized_voter_pubkey, true),
423    ];
424
425    Instruction::new_with_bincode(
426        id(),
427        &VoteInstruction::UpdateVoteStateSwitch(vote_state_update, proof_hash),
428        account_metas,
429    )
430}
431
432pub fn compact_update_vote_state(
433    vote_pubkey: &Pubkey,
434    authorized_voter_pubkey: &Pubkey,
435    vote_state_update: VoteStateUpdate,
436) -> Instruction {
437    let account_metas = vec![
438        AccountMeta::new(*vote_pubkey, false),
439        AccountMeta::new_readonly(*authorized_voter_pubkey, true),
440    ];
441
442    Instruction::new_with_bincode(
443        id(),
444        &VoteInstruction::CompactUpdateVoteState(vote_state_update),
445        account_metas,
446    )
447}
448
449pub fn compact_update_vote_state_switch(
450    vote_pubkey: &Pubkey,
451    authorized_voter_pubkey: &Pubkey,
452    vote_state_update: VoteStateUpdate,
453    proof_hash: Hash,
454) -> Instruction {
455    let account_metas = vec![
456        AccountMeta::new(*vote_pubkey, false),
457        AccountMeta::new_readonly(*authorized_voter_pubkey, true),
458    ];
459
460    Instruction::new_with_bincode(
461        id(),
462        &VoteInstruction::CompactUpdateVoteStateSwitch(vote_state_update, proof_hash),
463        account_metas,
464    )
465}
466
467pub fn withdraw(
468    vote_pubkey: &Pubkey,
469    authorized_withdrawer_pubkey: &Pubkey,
470    scoobies: u64,
471    to_pubkey: &Pubkey,
472) -> Instruction {
473    let account_metas = vec![
474        AccountMeta::new(*vote_pubkey, false),
475        AccountMeta::new(*to_pubkey, false),
476        AccountMeta::new_readonly(*authorized_withdrawer_pubkey, true),
477    ];
478
479    Instruction::new_with_bincode(id(), &VoteInstruction::Withdraw(scoobies), account_metas)
480}