Skip to content

Commit

Permalink
Add vote/stake checked instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
mvines authored and mergify[bot] committed Jul 6, 2021
1 parent 100fabf commit ee219ff
Show file tree
Hide file tree
Showing 4 changed files with 365 additions and 9 deletions.
117 changes: 108 additions & 9 deletions programs/stake/src/stake_instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ use {
process_instruction::{get_sysvar, InvokeContext},
program_utils::limited_deserialize,
pubkey::Pubkey,
stake::{instruction::StakeInstruction, program::id},
stake::{
instruction::StakeInstruction,
program::id,
state::{Authorized, Lockup},
},
sysvar::{self, clock::Clock, rent::Rent, stake_history::StakeHistory},
},
};
Expand Down Expand Up @@ -56,16 +60,17 @@ pub fn process_instruction(
let clock =
from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 1)?)?;
let _current_authority = keyed_account_at_index(keyed_accounts, 2)?;
let custodian =
keyed_account_at_index(keyed_accounts, 3).map(|ka| ka.unsigned_key());
let custodian = keyed_account_at_index(keyed_accounts, 3)
.ok()
.map(|ka| ka.unsigned_key());

me.authorize(
&signers,
&authorized_pubkey,
stake_authorize,
require_custodian_for_locked_stake_authorize,
&clock,
custodian.ok(),
custodian,
)
} else {
me.authorize(
Expand All @@ -87,8 +92,9 @@ pub fn process_instruction(
if require_custodian_for_locked_stake_authorize {
let clock =
from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 2)?)?;
let custodian =
keyed_account_at_index(keyed_accounts, 3).map(|ka| ka.unsigned_key());
let custodian = keyed_account_at_index(keyed_accounts, 3)
.ok()
.map(|ka| ka.unsigned_key());

me.authorize_with_seed(
authority_base,
Expand All @@ -98,7 +104,7 @@ pub fn process_instruction(
args.stake_authorize,
require_custodian_for_locked_stake_authorize,
&clock,
custodian.ok(),
custodian,
)
} else {
me.authorize_with_seed(
Expand Down Expand Up @@ -144,7 +150,6 @@ pub fn process_instruction(
can_merge_expired_lockups,
)
}

StakeInstruction::Withdraw(lamports) => {
let to = &keyed_account_at_index(keyed_accounts, 1)?;
me.withdraw(
Expand All @@ -161,7 +166,6 @@ pub fn process_instruction(
&from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 1)?)?,
&signers,
),

StakeInstruction::SetLockup(lockup) => {
let clock = if invoke_context.is_feature_active(&feature_set::stake_program_v4::id()) {
Some(get_sysvar::<Clock>(invoke_context, &sysvar::clock::id())?)
Expand All @@ -170,6 +174,101 @@ pub fn process_instruction(
};
me.set_lockup(&lockup, &signers, clock.as_ref())
}
StakeInstruction::InitializeChecked => {
if invoke_context.is_feature_active(&feature_set::vote_stake_checked_instructions::id())
{
let authorized = Authorized {
staker: *keyed_account_at_index(keyed_accounts, 2)?.unsigned_key(),
withdrawer: *keyed_account_at_index(keyed_accounts, 3)?
.signer_key()
.ok_or(InstructionError::MissingRequiredSignature)?,
};

me.initialize(
&authorized,
&Lockup::default(),
&from_keyed_account::<Rent>(keyed_account_at_index(keyed_accounts, 1)?)?,
)
} else {
Err(InstructionError::InvalidInstructionData)
}
}
StakeInstruction::AuthorizeChecked(stake_authorize) => {
if invoke_context.is_feature_active(&feature_set::vote_stake_checked_instructions::id())
{
let clock =
from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 1)?)?;
let _current_authority = keyed_account_at_index(keyed_accounts, 2)?;
let authorized_pubkey = &keyed_account_at_index(keyed_accounts, 3)?
.signer_key()
.ok_or(InstructionError::MissingRequiredSignature)?;
let custodian = keyed_account_at_index(keyed_accounts, 4)
.ok()
.map(|ka| ka.unsigned_key());

me.authorize(
&signers,
authorized_pubkey,
stake_authorize,
true,
&clock,
custodian,
)
} else {
Err(InstructionError::InvalidInstructionData)
}
}
StakeInstruction::AuthorizeCheckedWithSeed(args) => {
if invoke_context.is_feature_active(&feature_set::vote_stake_checked_instructions::id())
{
let authority_base = keyed_account_at_index(keyed_accounts, 1)?;
let clock =
from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 2)?)?;
let authorized_pubkey = &keyed_account_at_index(keyed_accounts, 3)?
.signer_key()
.ok_or(InstructionError::MissingRequiredSignature)?;
let custodian = keyed_account_at_index(keyed_accounts, 4)
.ok()
.map(|ka| ka.unsigned_key());

me.authorize_with_seed(
authority_base,
&args.authority_seed,
&args.authority_owner,
authorized_pubkey,
args.stake_authorize,
true,
&clock,
custodian,
)
} else {
Err(InstructionError::InvalidInstructionData)
}
}
StakeInstruction::SetLockupChecked(lockup_checked) => {
if invoke_context.is_feature_active(&feature_set::vote_stake_checked_instructions::id())
{
let custodian = if let Ok(custodian) = keyed_account_at_index(keyed_accounts, 4) {
Some(
*custodian
.signer_key()
.ok_or(InstructionError::MissingRequiredSignature)?,
)
} else {
None
};

let lockup = LockupArgs {
unix_timestamp: lockup_checked.unix_timestamp,
epoch: lockup_checked.epoch,
custodian,
};
let clock = Some(get_sysvar::<Clock>(invoke_context, &sysvar::clock::id())?);
me.set_lockup(&lockup, &signers, clock.as_ref())
} else {
Err(InstructionError::InvalidInstructionData)
}
}
}
}

Expand Down
49 changes: 49 additions & 0 deletions programs/vote/src/vote_instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,18 @@ pub enum VoteInstruction {
/// 2. [] Clock sysvar
/// 3. [SIGNER] Vote authority
VoteSwitch(Vote, Hash),

/// Authorize a key to send votes or issue a withdrawal
///
/// This instruction behaves like `Authorize` with the additional requirement that the new vote
/// or withdraw authority must also be a signer.
///
/// # Account references
/// 0. [WRITE] Vote account to be updated with the Pubkey for authorization
/// 1. [] Clock sysvar
/// 2. [SIGNER] Vote or withdraw authority
/// 3. [SIGNER] New vote or withdraw authority
AuthorizeChecked(VoteAuthorize),
}

fn initialize_account(vote_pubkey: &Pubkey, vote_init: &VoteInit) -> Instruction {
Expand Down Expand Up @@ -182,6 +194,26 @@ pub fn authorize(
)
}

pub fn authorize_checked(
vote_pubkey: &Pubkey,
authorized_pubkey: &Pubkey, // currently authorized
new_authorized_pubkey: &Pubkey,
vote_authorize: VoteAuthorize,
) -> Instruction {
let account_metas = vec![
AccountMeta::new(*vote_pubkey, false),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(*authorized_pubkey, true),
AccountMeta::new_readonly(*new_authorized_pubkey, true),
];

Instruction::new_with_bincode(
id(),
&VoteInstruction::AuthorizeChecked(vote_authorize),
account_metas,
)
}

pub fn update_validator_identity(
vote_pubkey: &Pubkey,
authorized_withdrawer_pubkey: &Pubkey,
Expand Down Expand Up @@ -335,6 +367,23 @@ pub fn process_instruction(
let to = keyed_account_at_index(keyed_accounts, 1)?;
vote_state::withdraw(me, lamports, to, &signers)
}
VoteInstruction::AuthorizeChecked(vote_authorize) => {
if invoke_context.is_feature_active(&feature_set::vote_stake_checked_instructions::id())
{
let voter_pubkey = &keyed_account_at_index(keyed_accounts, 3)?
.signer_key()
.ok_or(InstructionError::MissingRequiredSignature)?;
vote_state::authorize(
me,
voter_pubkey,
vote_authorize,
&signers,
&from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 1)?)?,
)
} else {
Err(InstructionError::InvalidInstructionData)
}
}
}
}

Expand Down
Loading

0 comments on commit ee219ff

Please sign in to comment.