reestablish parameter semantics for withdraw (#6330)
This commit is contained in:
parent
3313b2ff58
commit
c2ebf466fd
|
@ -7,9 +7,9 @@ use log::*;
|
||||||
use num_derive::{FromPrimitive, ToPrimitive};
|
use num_derive::{FromPrimitive, ToPrimitive};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::KeyedAccount,
|
account::{get_signers, KeyedAccount},
|
||||||
instruction::{AccountMeta, Instruction, InstructionError},
|
instruction::{AccountMeta, Instruction, InstructionError},
|
||||||
instruction_processor_utils::DecodeError,
|
instruction_processor_utils::{next_keyed_account, DecodeError},
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
system_instruction, sysvar,
|
system_instruction, sysvar,
|
||||||
sysvar::rent,
|
sysvar::rent,
|
||||||
|
@ -164,28 +164,24 @@ pub fn create_stake_account_and_delegate_stake(
|
||||||
instructions
|
instructions
|
||||||
}
|
}
|
||||||
|
|
||||||
// for instructions that whose authorized signer may differ from the account's pubkey
|
// for instructions whose authorized signer may already be in account parameters
|
||||||
fn metas_for_authorized_signer(
|
fn metas_with_signer(
|
||||||
account_pubkey: &Pubkey,
|
metas: &[AccountMeta], // parameter metas, in order
|
||||||
authorized_signer: &Pubkey, // currently authorized
|
signer: &Pubkey, // might already appear in parameters
|
||||||
other_params: &[AccountMeta],
|
|
||||||
) -> Vec<AccountMeta> {
|
) -> Vec<AccountMeta> {
|
||||||
let is_own_signer = authorized_signer == account_pubkey;
|
let mut metas = metas.to_vec();
|
||||||
|
|
||||||
// vote account
|
for meta in metas.iter_mut() {
|
||||||
let mut account_metas = vec![AccountMeta::new(*account_pubkey, is_own_signer)];
|
if &meta.pubkey == signer {
|
||||||
|
meta.is_signer = true; // found it, we're done
|
||||||
for meta in other_params {
|
return metas;
|
||||||
account_metas.push(meta.clone());
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// append signer at the end
|
// signer wasn't in metas, append it after normal parameters
|
||||||
if !is_own_signer {
|
metas.push(AccountMeta::new_credit_only(*signer, true));
|
||||||
account_metas.push(AccountMeta::new_credit_only(*authorized_signer, true))
|
|
||||||
// signer
|
|
||||||
}
|
|
||||||
|
|
||||||
account_metas
|
metas
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn authorize(
|
pub fn authorize(
|
||||||
|
@ -194,7 +190,8 @@ pub fn authorize(
|
||||||
new_authorized_pubkey: &Pubkey,
|
new_authorized_pubkey: &Pubkey,
|
||||||
stake_authorize: StakeAuthorize,
|
stake_authorize: StakeAuthorize,
|
||||||
) -> Instruction {
|
) -> Instruction {
|
||||||
let account_metas = metas_for_authorized_signer(stake_pubkey, authorized_pubkey, &[]);
|
let account_metas =
|
||||||
|
metas_with_signer(&[AccountMeta::new(*stake_pubkey, false)], authorized_pubkey);
|
||||||
|
|
||||||
Instruction::new(
|
Instruction::new(
|
||||||
id(),
|
id(),
|
||||||
|
@ -219,14 +216,14 @@ pub fn delegate_stake(
|
||||||
authorized_pubkey: &Pubkey,
|
authorized_pubkey: &Pubkey,
|
||||||
vote_pubkey: &Pubkey,
|
vote_pubkey: &Pubkey,
|
||||||
) -> Instruction {
|
) -> Instruction {
|
||||||
let account_metas = metas_for_authorized_signer(
|
let account_metas = metas_with_signer(
|
||||||
stake_pubkey,
|
|
||||||
authorized_pubkey,
|
|
||||||
&[
|
&[
|
||||||
|
AccountMeta::new(*stake_pubkey, false),
|
||||||
AccountMeta::new_credit_only(*vote_pubkey, false),
|
AccountMeta::new_credit_only(*vote_pubkey, false),
|
||||||
AccountMeta::new_credit_only(sysvar::clock::id(), false),
|
AccountMeta::new_credit_only(sysvar::clock::id(), false),
|
||||||
AccountMeta::new_credit_only(crate::config::id(), false),
|
AccountMeta::new_credit_only(crate::config::id(), false),
|
||||||
],
|
],
|
||||||
|
authorized_pubkey,
|
||||||
);
|
);
|
||||||
Instruction::new(id(), &StakeInstruction::DelegateStake, account_metas)
|
Instruction::new(id(), &StakeInstruction::DelegateStake, account_metas)
|
||||||
}
|
}
|
||||||
|
@ -237,22 +234,25 @@ pub fn withdraw(
|
||||||
to_pubkey: &Pubkey,
|
to_pubkey: &Pubkey,
|
||||||
lamports: u64,
|
lamports: u64,
|
||||||
) -> Instruction {
|
) -> Instruction {
|
||||||
let mut accounts = vec![
|
let account_metas = metas_with_signer(
|
||||||
AccountMeta::new_credit_only(sysvar::clock::id(), false),
|
&[
|
||||||
AccountMeta::new_credit_only(sysvar::stake_history::id(), false),
|
AccountMeta::new(*stake_pubkey, false),
|
||||||
];
|
AccountMeta::new_credit_only(*to_pubkey, false),
|
||||||
if to_pubkey != authorized_pubkey {
|
AccountMeta::new_credit_only(sysvar::clock::id(), false),
|
||||||
accounts.push(AccountMeta::new_credit_only(*to_pubkey, false));
|
AccountMeta::new_credit_only(sysvar::stake_history::id(), false),
|
||||||
}
|
],
|
||||||
let account_metas = metas_for_authorized_signer(stake_pubkey, authorized_pubkey, &accounts);
|
authorized_pubkey,
|
||||||
|
);
|
||||||
Instruction::new(id(), &StakeInstruction::Withdraw(lamports), account_metas)
|
Instruction::new(id(), &StakeInstruction::Withdraw(lamports), account_metas)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deactivate_stake(stake_pubkey: &Pubkey, authorized_pubkey: &Pubkey) -> Instruction {
|
pub fn deactivate_stake(stake_pubkey: &Pubkey, authorized_pubkey: &Pubkey) -> Instruction {
|
||||||
let account_metas = metas_for_authorized_signer(
|
let account_metas = metas_with_signer(
|
||||||
stake_pubkey,
|
&[
|
||||||
|
AccountMeta::new(*stake_pubkey, false),
|
||||||
|
AccountMeta::new_credit_only(sysvar::clock::id(), false),
|
||||||
|
],
|
||||||
authorized_pubkey,
|
authorized_pubkey,
|
||||||
&[AccountMeta::new_credit_only(sysvar::clock::id(), false)],
|
|
||||||
);
|
);
|
||||||
Instruction::new(id(), &StakeInstruction::Deactivate, account_metas)
|
Instruction::new(id(), &StakeInstruction::Deactivate, account_metas)
|
||||||
}
|
}
|
||||||
|
@ -267,73 +267,55 @@ pub fn process_instruction(
|
||||||
trace!("process_instruction: {:?}", data);
|
trace!("process_instruction: {:?}", data);
|
||||||
trace!("keyed_accounts: {:?}", keyed_accounts);
|
trace!("keyed_accounts: {:?}", keyed_accounts);
|
||||||
|
|
||||||
if keyed_accounts.is_empty() {
|
let signers = get_signers(keyed_accounts);
|
||||||
return Err(InstructionError::InvalidInstructionData);
|
|
||||||
}
|
|
||||||
|
|
||||||
let (me, rest) = &mut keyed_accounts.split_at_mut(1);
|
let keyed_accounts = &mut keyed_accounts.iter_mut();
|
||||||
let me = &mut me[0];
|
let me = &mut next_keyed_account(keyed_accounts)?;
|
||||||
|
|
||||||
// TODO: data-driven unpack and dispatch of KeyedAccounts
|
// TODO: data-driven unpack and dispatch of KeyedAccounts
|
||||||
match deserialize(data).map_err(|_| InstructionError::InvalidInstructionData)? {
|
match deserialize(data).map_err(|_| InstructionError::InvalidInstructionData)? {
|
||||||
StakeInstruction::Initialize(authorized, lockup) => {
|
StakeInstruction::Initialize(authorized, lockup) => {
|
||||||
if rest.is_empty() {
|
rent::verify_rent_exemption(me, next_keyed_account(keyed_accounts)?)?;
|
||||||
return Err(InstructionError::InvalidInstructionData);
|
|
||||||
}
|
|
||||||
rent::verify_rent_exemption(me, &rest[0])?;
|
|
||||||
me.initialize(&authorized, &lockup)
|
me.initialize(&authorized, &lockup)
|
||||||
}
|
}
|
||||||
StakeInstruction::Authorize(authorized_pubkey, stake_authorize) => {
|
StakeInstruction::Authorize(authorized_pubkey, stake_authorize) => {
|
||||||
me.authorize(&authorized_pubkey, stake_authorize, &rest)
|
me.authorize(&authorized_pubkey, stake_authorize, &signers)
|
||||||
}
|
}
|
||||||
StakeInstruction::DelegateStake => {
|
StakeInstruction::DelegateStake => {
|
||||||
if rest.len() < 3 {
|
let vote = next_keyed_account(keyed_accounts)?;
|
||||||
return Err(InstructionError::InvalidInstructionData);
|
|
||||||
}
|
|
||||||
let vote = &rest[0];
|
|
||||||
|
|
||||||
me.delegate_stake(
|
me.delegate_stake(
|
||||||
vote,
|
&vote,
|
||||||
&sysvar::clock::from_keyed_account(&rest[1])?,
|
&sysvar::clock::from_keyed_account(next_keyed_account(keyed_accounts)?)?,
|
||||||
&config::from_keyed_account(&rest[2])?,
|
&config::from_keyed_account(next_keyed_account(keyed_accounts)?)?,
|
||||||
&rest[3..],
|
&signers,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
StakeInstruction::RedeemVoteCredits => {
|
StakeInstruction::RedeemVoteCredits => {
|
||||||
if rest.len() != 4 {
|
let vote = &mut next_keyed_account(keyed_accounts)?;
|
||||||
return Err(InstructionError::InvalidInstructionData);
|
let rewards_pool = &mut next_keyed_account(keyed_accounts)?;
|
||||||
}
|
|
||||||
let (vote, rest) = rest.split_at_mut(1);
|
|
||||||
let vote = &mut vote[0];
|
|
||||||
let (rewards_pool, rest) = rest.split_at_mut(1);
|
|
||||||
let rewards_pool = &mut rewards_pool[0];
|
|
||||||
|
|
||||||
me.redeem_vote_credits(
|
me.redeem_vote_credits(
|
||||||
vote,
|
vote,
|
||||||
rewards_pool,
|
rewards_pool,
|
||||||
&sysvar::rewards::from_keyed_account(&rest[0])?,
|
&sysvar::rewards::from_keyed_account(next_keyed_account(keyed_accounts)?)?,
|
||||||
&sysvar::stake_history::from_keyed_account(&rest[1])?,
|
&sysvar::stake_history::from_keyed_account(next_keyed_account(keyed_accounts)?)?,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
StakeInstruction::Withdraw(lamports) => {
|
StakeInstruction::Withdraw(lamports) => {
|
||||||
if rest.len() < 3 {
|
let to = &mut next_keyed_account(keyed_accounts)?;
|
||||||
return Err(InstructionError::InvalidInstructionData);
|
|
||||||
}
|
|
||||||
|
|
||||||
me.withdraw(
|
me.withdraw(
|
||||||
lamports,
|
lamports,
|
||||||
&sysvar::clock::from_keyed_account(&rest[0])?,
|
to,
|
||||||
&sysvar::stake_history::from_keyed_account(&rest[1])?,
|
&sysvar::clock::from_keyed_account(next_keyed_account(keyed_accounts)?)?,
|
||||||
&mut rest[2..],
|
&sysvar::stake_history::from_keyed_account(next_keyed_account(keyed_accounts)?)?,
|
||||||
|
&signers,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
StakeInstruction::Deactivate => {
|
StakeInstruction::Deactivate => me.deactivate_stake(
|
||||||
if rest.is_empty() {
|
&sysvar::clock::from_keyed_account(next_keyed_account(keyed_accounts)?)?,
|
||||||
return Err(InstructionError::InvalidInstructionData);
|
&signers,
|
||||||
}
|
),
|
||||||
|
|
||||||
me.deactivate_stake(&sysvar::clock::from_keyed_account(&rest[0])?, &rest[1..])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,7 +403,7 @@ mod tests {
|
||||||
))
|
))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
),
|
),
|
||||||
Err(InstructionError::InvalidInstructionData),
|
Err(InstructionError::NotEnoughAccountKeys),
|
||||||
);
|
);
|
||||||
|
|
||||||
// gets the first check in delegate, wrong number of accounts
|
// gets the first check in delegate, wrong number of accounts
|
||||||
|
@ -435,7 +417,7 @@ mod tests {
|
||||||
)],
|
)],
|
||||||
&serialize(&StakeInstruction::DelegateStake).unwrap(),
|
&serialize(&StakeInstruction::DelegateStake).unwrap(),
|
||||||
),
|
),
|
||||||
Err(InstructionError::InvalidInstructionData),
|
Err(InstructionError::NotEnoughAccountKeys),
|
||||||
);
|
);
|
||||||
|
|
||||||
// gets the sub-check for number of args
|
// gets the sub-check for number of args
|
||||||
|
@ -449,7 +431,7 @@ mod tests {
|
||||||
),],
|
),],
|
||||||
&serialize(&StakeInstruction::DelegateStake).unwrap(),
|
&serialize(&StakeInstruction::DelegateStake).unwrap(),
|
||||||
),
|
),
|
||||||
Err(InstructionError::InvalidInstructionData),
|
Err(InstructionError::NotEnoughAccountKeys),
|
||||||
);
|
);
|
||||||
|
|
||||||
// catches the number of args check
|
// catches the number of args check
|
||||||
|
@ -462,7 +444,7 @@ mod tests {
|
||||||
],
|
],
|
||||||
&serialize(&StakeInstruction::RedeemVoteCredits).unwrap(),
|
&serialize(&StakeInstruction::RedeemVoteCredits).unwrap(),
|
||||||
),
|
),
|
||||||
Err(InstructionError::InvalidInstructionData),
|
Err(InstructionError::NotEnoughAccountKeys),
|
||||||
);
|
);
|
||||||
|
|
||||||
// catches the type of args check
|
// catches the type of args check
|
||||||
|
@ -555,22 +537,14 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
super::process_instruction(
|
super::process_instruction(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&mut [
|
&mut [KeyedAccount::new(
|
||||||
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
|
&Pubkey::default(),
|
||||||
KeyedAccount::new(
|
false,
|
||||||
&sysvar::clock::id(),
|
&mut Account::default()
|
||||||
false,
|
)],
|
||||||
&mut sysvar::rewards::create_account(1, 0.0, 0.0)
|
|
||||||
),
|
|
||||||
KeyedAccount::new(
|
|
||||||
&sysvar::stake_history::id(),
|
|
||||||
false,
|
|
||||||
&mut sysvar::stake_history::create_account(1, &StakeHistory::default())
|
|
||||||
),
|
|
||||||
],
|
|
||||||
&serialize(&StakeInstruction::Withdraw(42)).unwrap(),
|
&serialize(&StakeInstruction::Withdraw(42)).unwrap(),
|
||||||
),
|
),
|
||||||
Err(InstructionError::InvalidInstructionData),
|
Err(InstructionError::NotEnoughAccountKeys),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Tests 2nd keyed account is of correct type (Clock instead of rewards) in deactivate
|
// Tests 2nd keyed account is of correct type (Clock instead of rewards) in deactivate
|
||||||
|
@ -594,14 +568,10 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
super::process_instruction(
|
super::process_instruction(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&mut [KeyedAccount::new(
|
&mut [],
|
||||||
&sysvar::clock::id(),
|
|
||||||
false,
|
|
||||||
&mut sysvar::rewards::create_account(1, 0.0, 0.0)
|
|
||||||
),],
|
|
||||||
&serialize(&StakeInstruction::Deactivate).unwrap(),
|
&serialize(&StakeInstruction::Deactivate).unwrap(),
|
||||||
),
|
),
|
||||||
Err(InstructionError::InvalidInstructionData),
|
Err(InstructionError::NotEnoughAccountKeys),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ use solana_sdk::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use solana_vote_api::vote_state::VoteState;
|
use solana_vote_api::vote_state::VoteState;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Copy)]
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Copy)]
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
|
@ -134,32 +135,23 @@ impl Authorized {
|
||||||
}
|
}
|
||||||
pub fn check(
|
pub fn check(
|
||||||
&self,
|
&self,
|
||||||
stake_signer: Option<&Pubkey>,
|
signers: &HashSet<Pubkey>,
|
||||||
other_signers: &[KeyedAccount],
|
|
||||||
stake_authorize: StakeAuthorize,
|
stake_authorize: StakeAuthorize,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
let authorized = match stake_authorize {
|
match stake_authorize {
|
||||||
StakeAuthorize::Staker => Some(&self.staker),
|
StakeAuthorize::Staker if signers.contains(&self.staker) => Ok(()),
|
||||||
StakeAuthorize::Withdrawer => Some(&self.withdrawer),
|
StakeAuthorize::Withdrawer if signers.contains(&self.withdrawer) => Ok(()),
|
||||||
};
|
_ => Err(InstructionError::MissingRequiredSignature),
|
||||||
if stake_signer != authorized
|
|
||||||
&& other_signers
|
|
||||||
.iter()
|
|
||||||
.all(|account| account.signer_key() != authorized)
|
|
||||||
{
|
|
||||||
Err(InstructionError::MissingRequiredSignature)
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn authorize(
|
pub fn authorize(
|
||||||
&mut self,
|
&mut self,
|
||||||
stake_signer: Option<&Pubkey>,
|
signers: &HashSet<Pubkey>,
|
||||||
other_signers: &[KeyedAccount],
|
|
||||||
new_authorized: &Pubkey,
|
new_authorized: &Pubkey,
|
||||||
stake_authorize: StakeAuthorize,
|
stake_authorize: StakeAuthorize,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
self.check(stake_signer, other_signers, stake_authorize)?;
|
self.check(signers, stake_authorize)?;
|
||||||
match stake_authorize {
|
match stake_authorize {
|
||||||
StakeAuthorize::Staker => self.staker = *new_authorized,
|
StakeAuthorize::Staker => self.staker = *new_authorized,
|
||||||
StakeAuthorize::Withdrawer => self.withdrawer = *new_authorized,
|
StakeAuthorize::Withdrawer => self.withdrawer = *new_authorized,
|
||||||
|
@ -419,19 +411,19 @@ pub trait StakeAccount {
|
||||||
&mut self,
|
&mut self,
|
||||||
authority: &Pubkey,
|
authority: &Pubkey,
|
||||||
stake_authorize: StakeAuthorize,
|
stake_authorize: StakeAuthorize,
|
||||||
other_signers: &[KeyedAccount],
|
signers: &HashSet<Pubkey>,
|
||||||
) -> Result<(), InstructionError>;
|
) -> Result<(), InstructionError>;
|
||||||
fn delegate_stake(
|
fn delegate_stake(
|
||||||
&mut self,
|
&mut self,
|
||||||
vote_account: &KeyedAccount,
|
vote_account: &KeyedAccount,
|
||||||
clock: &sysvar::clock::Clock,
|
clock: &sysvar::clock::Clock,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
other_signers: &[KeyedAccount],
|
signers: &HashSet<Pubkey>,
|
||||||
) -> Result<(), InstructionError>;
|
) -> Result<(), InstructionError>;
|
||||||
fn deactivate_stake(
|
fn deactivate_stake(
|
||||||
&mut self,
|
&mut self,
|
||||||
clock: &sysvar::clock::Clock,
|
clock: &sysvar::clock::Clock,
|
||||||
other_signers: &[KeyedAccount],
|
signers: &HashSet<Pubkey>,
|
||||||
) -> Result<(), InstructionError>;
|
) -> Result<(), InstructionError>;
|
||||||
fn redeem_vote_credits(
|
fn redeem_vote_credits(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -443,9 +435,10 @@ pub trait StakeAccount {
|
||||||
fn withdraw(
|
fn withdraw(
|
||||||
&mut self,
|
&mut self,
|
||||||
lamports: u64,
|
lamports: u64,
|
||||||
|
to: &mut KeyedAccount,
|
||||||
clock: &sysvar::clock::Clock,
|
clock: &sysvar::clock::Clock,
|
||||||
stake_history: &sysvar::stake_history::StakeHistory,
|
stake_history: &sysvar::stake_history::StakeHistory,
|
||||||
recipient_and_signer_accounts: &mut [KeyedAccount],
|
signers: &HashSet<Pubkey>,
|
||||||
) -> Result<(), InstructionError>;
|
) -> Result<(), InstructionError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,15 +461,15 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
authority: &Pubkey,
|
authority: &Pubkey,
|
||||||
stake_authorize: StakeAuthorize,
|
stake_authorize: StakeAuthorize,
|
||||||
other_signers: &[KeyedAccount],
|
signers: &HashSet<Pubkey>,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
let stake_state = self.state()?;
|
let stake_state = self.state()?;
|
||||||
|
|
||||||
if let StakeState::Stake(mut authorized, lockup, stake) = stake_state {
|
if let StakeState::Stake(mut authorized, lockup, stake) = stake_state {
|
||||||
authorized.authorize(self.signer_key(), other_signers, authority, stake_authorize)?;
|
authorized.authorize(signers, authority, stake_authorize)?;
|
||||||
self.set_state(&StakeState::Stake(authorized, lockup, stake))
|
self.set_state(&StakeState::Stake(authorized, lockup, stake))
|
||||||
} else if let StakeState::Initialized(mut authorized, lockup) = stake_state {
|
} else if let StakeState::Initialized(mut authorized, lockup) = stake_state {
|
||||||
authorized.authorize(self.signer_key(), other_signers, authority, stake_authorize)?;
|
authorized.authorize(signers, authority, stake_authorize)?;
|
||||||
self.set_state(&StakeState::Initialized(authorized, lockup))
|
self.set_state(&StakeState::Initialized(authorized, lockup))
|
||||||
} else {
|
} else {
|
||||||
Err(InstructionError::InvalidAccountData)
|
Err(InstructionError::InvalidAccountData)
|
||||||
|
@ -487,10 +480,10 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
||||||
vote_account: &KeyedAccount,
|
vote_account: &KeyedAccount,
|
||||||
clock: &sysvar::clock::Clock,
|
clock: &sysvar::clock::Clock,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
other_signers: &[KeyedAccount],
|
signers: &HashSet<Pubkey>,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
if let StakeState::Initialized(authorized, lockup) = self.state()? {
|
if let StakeState::Initialized(authorized, lockup) = self.state()? {
|
||||||
authorized.check(self.signer_key(), other_signers, StakeAuthorize::Staker)?;
|
authorized.check(signers, StakeAuthorize::Staker)?;
|
||||||
let stake = Stake::new(
|
let stake = Stake::new(
|
||||||
self.account.lamports,
|
self.account.lamports,
|
||||||
vote_account.unsigned_key(),
|
vote_account.unsigned_key(),
|
||||||
|
@ -501,7 +494,7 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
||||||
|
|
||||||
self.set_state(&StakeState::Stake(authorized, lockup, stake))
|
self.set_state(&StakeState::Stake(authorized, lockup, stake))
|
||||||
} else if let StakeState::Stake(authorized, lockup, mut stake) = self.state()? {
|
} else if let StakeState::Stake(authorized, lockup, mut stake) = self.state()? {
|
||||||
authorized.check(self.signer_key(), other_signers, StakeAuthorize::Staker)?;
|
authorized.check(signers, StakeAuthorize::Staker)?;
|
||||||
stake.redelegate(
|
stake.redelegate(
|
||||||
vote_account.unsigned_key(),
|
vote_account.unsigned_key(),
|
||||||
&vote_account.state()?,
|
&vote_account.state()?,
|
||||||
|
@ -515,10 +508,10 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
||||||
fn deactivate_stake(
|
fn deactivate_stake(
|
||||||
&mut self,
|
&mut self,
|
||||||
clock: &sysvar::clock::Clock,
|
clock: &sysvar::clock::Clock,
|
||||||
other_signers: &[KeyedAccount],
|
signers: &HashSet<Pubkey>,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
if let StakeState::Stake(authorized, lockup, mut stake) = self.state()? {
|
if let StakeState::Stake(authorized, lockup, mut stake) = self.state()? {
|
||||||
authorized.check(self.signer_key(), other_signers, StakeAuthorize::Staker)?;
|
authorized.check(signers, StakeAuthorize::Staker)?;
|
||||||
stake.deactivate(clock.epoch);
|
stake.deactivate(clock.epoch);
|
||||||
|
|
||||||
self.set_state(&StakeState::Stake(authorized, lockup, stake))
|
self.set_state(&StakeState::Stake(authorized, lockup, stake))
|
||||||
|
@ -574,17 +567,14 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
||||||
fn withdraw(
|
fn withdraw(
|
||||||
&mut self,
|
&mut self,
|
||||||
lamports: u64,
|
lamports: u64,
|
||||||
|
to: &mut KeyedAccount,
|
||||||
clock: &sysvar::clock::Clock,
|
clock: &sysvar::clock::Clock,
|
||||||
stake_history: &sysvar::stake_history::StakeHistory,
|
stake_history: &sysvar::stake_history::StakeHistory,
|
||||||
recipient_and_signer_accounts: &mut [KeyedAccount],
|
signers: &HashSet<Pubkey>,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
let lockup = match self.state()? {
|
let lockup = match self.state()? {
|
||||||
StakeState::Stake(authorized, lockup, stake) => {
|
StakeState::Stake(authorized, lockup, stake) => {
|
||||||
authorized.check(
|
authorized.check(signers, StakeAuthorize::Withdrawer)?;
|
||||||
self.signer_key(),
|
|
||||||
recipient_and_signer_accounts,
|
|
||||||
StakeAuthorize::Withdrawer,
|
|
||||||
)?;
|
|
||||||
// if we have a deactivation epoch and we're in cooldown
|
// if we have a deactivation epoch and we're in cooldown
|
||||||
let staked = if clock.epoch >= stake.deactivation_epoch {
|
let staked = if clock.epoch >= stake.deactivation_epoch {
|
||||||
stake.stake(clock.epoch, Some(stake_history))
|
stake.stake(clock.epoch, Some(stake_history))
|
||||||
|
@ -601,11 +591,7 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
||||||
lockup
|
lockup
|
||||||
}
|
}
|
||||||
StakeState::Initialized(authorized, lockup) => {
|
StakeState::Initialized(authorized, lockup) => {
|
||||||
authorized.check(
|
authorized.check(signers, StakeAuthorize::Withdrawer)?;
|
||||||
self.signer_key(),
|
|
||||||
recipient_and_signer_accounts,
|
|
||||||
StakeAuthorize::Withdrawer,
|
|
||||||
)?;
|
|
||||||
lockup
|
lockup
|
||||||
}
|
}
|
||||||
StakeState::Uninitialized => {
|
StakeState::Uninitialized => {
|
||||||
|
@ -616,7 +602,6 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
||||||
}
|
}
|
||||||
_ => return Err(InstructionError::InvalidAccountData),
|
_ => return Err(InstructionError::InvalidAccountData),
|
||||||
};
|
};
|
||||||
let mut to = &mut recipient_and_signer_accounts[0];
|
|
||||||
|
|
||||||
if lockup.slot > clock.slot && lockup.custodian != *to.unsigned_key() {
|
if lockup.slot > clock.slot && lockup.custodian != *to.unsigned_key() {
|
||||||
return Err(StakeError::LockupInForce.into());
|
return Err(StakeError::LockupInForce.into());
|
||||||
|
@ -770,20 +755,22 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut signers = HashSet::default();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.delegate_stake(
|
stake_keyed_account.delegate_stake(
|
||||||
&vote_keyed_account,
|
&vote_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&Config::default(),
|
&Config::default(),
|
||||||
&[]
|
&signers,
|
||||||
),
|
),
|
||||||
Err(InstructionError::MissingRequiredSignature)
|
Err(InstructionError::MissingRequiredSignature)
|
||||||
);
|
);
|
||||||
|
|
||||||
// signed keyed account
|
// signed keyed account
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
||||||
|
signers.insert(stake_pubkey);
|
||||||
assert!(stake_keyed_account
|
assert!(stake_keyed_account
|
||||||
.delegate_stake(&vote_keyed_account, &clock, &Config::default(), &[])
|
.delegate_stake(&vote_keyed_account, &clock, &Config::default(), &signers,)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
|
||||||
// verify that delegate_stake() looks right, compare against hand-rolled
|
// verify that delegate_stake() looks right, compare against hand-rolled
|
||||||
|
@ -808,7 +795,7 @@ mod tests {
|
||||||
|
|
||||||
// verify that delegate_stake can be called twice, 2nd is redelegate
|
// verify that delegate_stake can be called twice, 2nd is redelegate
|
||||||
assert!(stake_keyed_account
|
assert!(stake_keyed_account
|
||||||
.delegate_stake(&vote_keyed_account, &clock, &Config::default(), &[])
|
.delegate_stake(&vote_keyed_account, &clock, &Config::default(), &signers)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
|
||||||
// verify that non-stakes fail delegate_stake()
|
// verify that non-stakes fail delegate_stake()
|
||||||
|
@ -816,7 +803,7 @@ mod tests {
|
||||||
|
|
||||||
stake_keyed_account.set_state(&stake_state).unwrap();
|
stake_keyed_account.set_state(&stake_state).unwrap();
|
||||||
assert!(stake_keyed_account
|
assert!(stake_keyed_account
|
||||||
.delegate_stake(&vote_keyed_account, &clock, &Config::default(), &[])
|
.delegate_stake(&vote_keyed_account, &clock, &Config::default(), &signers)
|
||||||
.is_err());
|
.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1163,8 +1150,9 @@ mod tests {
|
||||||
|
|
||||||
// signed keyed account but not staked yet
|
// signed keyed account but not staked yet
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
||||||
|
let signers = vec![stake_pubkey].into_iter().collect();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.deactivate_stake(&clock, &[]),
|
stake_keyed_account.deactivate_stake(&clock, &signers),
|
||||||
Err(InstructionError::InvalidAccountData)
|
Err(InstructionError::InvalidAccountData)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1179,21 +1167,24 @@ mod tests {
|
||||||
&vote_keyed_account,
|
&vote_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&Config::default(),
|
&Config::default(),
|
||||||
&[]
|
&signers
|
||||||
),
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
|
||||||
// unsigned keyed account
|
// no signers fails
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, false, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, false, &mut stake_account);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.deactivate_stake(&clock, &[]),
|
stake_keyed_account.deactivate_stake(&clock, &HashSet::default()),
|
||||||
Err(InstructionError::MissingRequiredSignature)
|
Err(InstructionError::MissingRequiredSignature)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Deactivate after staking
|
// Deactivate after staking
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
||||||
assert_eq!(stake_keyed_account.deactivate_stake(&clock, &[]), Ok(()));
|
assert_eq!(
|
||||||
|
stake_keyed_account.deactivate_stake(&clock, &signers),
|
||||||
|
Ok(())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1212,29 +1203,32 @@ mod tests {
|
||||||
|
|
||||||
let to = Pubkey::new_rand();
|
let to = Pubkey::new_rand();
|
||||||
let mut to_account = Account::new(1, 0, &system_program::id());
|
let mut to_account = Account::new(1, 0, &system_program::id());
|
||||||
let to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
||||||
|
|
||||||
// unsigned keyed account should fail
|
// no signers, should fail
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, false, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, false, &mut stake_account);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.withdraw(
|
stake_keyed_account.withdraw(
|
||||||
stake_lamports,
|
stake_lamports,
|
||||||
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default(),
|
&StakeHistory::default(),
|
||||||
&mut [to_keyed_account],
|
&HashSet::default(),
|
||||||
),
|
),
|
||||||
Err(InstructionError::MissingRequiredSignature)
|
Err(InstructionError::MissingRequiredSignature)
|
||||||
);
|
);
|
||||||
|
|
||||||
// signed keyed account and uninitialized should work
|
// signed keyed account and uninitialized should work
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
||||||
let to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
||||||
|
let signers = vec![stake_pubkey].into_iter().collect();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.withdraw(
|
stake_keyed_account.withdraw(
|
||||||
stake_lamports,
|
stake_lamports,
|
||||||
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default(),
|
&StakeHistory::default(),
|
||||||
&mut [to_keyed_account],
|
&signers,
|
||||||
),
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
@ -1255,13 +1249,14 @@ mod tests {
|
||||||
|
|
||||||
// signed keyed account and locked up, more than available should fail
|
// signed keyed account and locked up, more than available should fail
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
||||||
let to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.withdraw(
|
stake_keyed_account.withdraw(
|
||||||
stake_lamports + 1,
|
stake_lamports + 1,
|
||||||
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default(),
|
&StakeHistory::default(),
|
||||||
&mut [to_keyed_account],
|
&signers,
|
||||||
),
|
),
|
||||||
Err(InstructionError::InsufficientFunds)
|
Err(InstructionError::InsufficientFunds)
|
||||||
);
|
);
|
||||||
|
@ -1277,7 +1272,7 @@ mod tests {
|
||||||
&vote_keyed_account,
|
&vote_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&Config::default(),
|
&Config::default(),
|
||||||
&[]
|
&signers,
|
||||||
),
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
@ -1286,13 +1281,14 @@ mod tests {
|
||||||
stake_account.lamports += 10;
|
stake_account.lamports += 10;
|
||||||
// withdrawal before deactivate works for rewards amount
|
// withdrawal before deactivate works for rewards amount
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
||||||
let to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.withdraw(
|
stake_keyed_account.withdraw(
|
||||||
10,
|
10,
|
||||||
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default(),
|
&StakeHistory::default(),
|
||||||
&mut [to_keyed_account],
|
&signers,
|
||||||
),
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
@ -1301,42 +1297,48 @@ mod tests {
|
||||||
stake_account.lamports += 10;
|
stake_account.lamports += 10;
|
||||||
// withdrawal of rewards fails if not in excess of stake
|
// withdrawal of rewards fails if not in excess of stake
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
||||||
let to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.withdraw(
|
stake_keyed_account.withdraw(
|
||||||
10 + 1,
|
10 + 1,
|
||||||
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default(),
|
&StakeHistory::default(),
|
||||||
&mut [to_keyed_account],
|
&signers
|
||||||
),
|
),
|
||||||
Err(InstructionError::InsufficientFunds)
|
Err(InstructionError::InsufficientFunds)
|
||||||
);
|
);
|
||||||
|
|
||||||
// deactivate the stake before withdrawal
|
// deactivate the stake before withdrawal
|
||||||
assert_eq!(stake_keyed_account.deactivate_stake(&clock, &[]), Ok(()));
|
assert_eq!(
|
||||||
|
stake_keyed_account.deactivate_stake(&clock, &signers),
|
||||||
|
Ok(())
|
||||||
|
);
|
||||||
// simulate time passing
|
// simulate time passing
|
||||||
clock.epoch += 100;
|
clock.epoch += 100;
|
||||||
|
|
||||||
// Try to withdraw more than what's available
|
// Try to withdraw more than what's available
|
||||||
let to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.withdraw(
|
stake_keyed_account.withdraw(
|
||||||
stake_lamports + 10 + 1,
|
stake_lamports + 10 + 1,
|
||||||
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default(),
|
&StakeHistory::default(),
|
||||||
&mut [to_keyed_account],
|
&signers
|
||||||
),
|
),
|
||||||
Err(InstructionError::InsufficientFunds)
|
Err(InstructionError::InsufficientFunds)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Try to withdraw all lamports
|
// Try to withdraw all lamports
|
||||||
let to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.withdraw(
|
stake_keyed_account.withdraw(
|
||||||
stake_lamports + 10,
|
stake_lamports + 10,
|
||||||
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default(),
|
&StakeHistory::default(),
|
||||||
&mut [to_keyed_account],
|
&signers
|
||||||
),
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
@ -1362,7 +1364,7 @@ mod tests {
|
||||||
|
|
||||||
let to = Pubkey::new_rand();
|
let to = Pubkey::new_rand();
|
||||||
let mut to_account = Account::new(1, 0, &system_program::id());
|
let mut to_account = Account::new(1, 0, &system_program::id());
|
||||||
let to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
||||||
|
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
||||||
|
|
||||||
|
@ -1372,12 +1374,13 @@ mod tests {
|
||||||
vote_state::create_account(&vote_pubkey, &Pubkey::new_rand(), 0, 100);
|
vote_state::create_account(&vote_pubkey, &Pubkey::new_rand(), 0, 100);
|
||||||
let mut vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &mut vote_account);
|
let mut vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &mut vote_account);
|
||||||
vote_keyed_account.set_state(&VoteState::default()).unwrap();
|
vote_keyed_account.set_state(&VoteState::default()).unwrap();
|
||||||
|
let signers = vec![stake_pubkey].into_iter().collect();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.delegate_stake(
|
stake_keyed_account.delegate_stake(
|
||||||
&vote_keyed_account,
|
&vote_keyed_account,
|
||||||
&future,
|
&future,
|
||||||
&Config::default(),
|
&Config::default(),
|
||||||
&[]
|
&signers,
|
||||||
),
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
@ -1392,9 +1395,10 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.withdraw(
|
stake_keyed_account.withdraw(
|
||||||
total_lamports - stake_lamports + 1,
|
total_lamports - stake_lamports + 1,
|
||||||
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&stake_history,
|
&stake_history,
|
||||||
&mut [to_keyed_account],
|
&signers,
|
||||||
),
|
),
|
||||||
Err(InstructionError::InsufficientFunds)
|
Err(InstructionError::InsufficientFunds)
|
||||||
);
|
);
|
||||||
|
@ -1414,15 +1418,16 @@ mod tests {
|
||||||
|
|
||||||
let to = Pubkey::new_rand();
|
let to = Pubkey::new_rand();
|
||||||
let mut to_account = Account::new(1, 0, &system_program::id());
|
let mut to_account = Account::new(1, 0, &system_program::id());
|
||||||
let to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
||||||
|
let signers = vec![stake_pubkey].into_iter().collect();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.withdraw(
|
stake_keyed_account.withdraw(
|
||||||
total_lamports,
|
total_lamports,
|
||||||
|
&mut to_keyed_account,
|
||||||
&sysvar::clock::Clock::default(),
|
&sysvar::clock::Clock::default(),
|
||||||
&StakeHistory::default(),
|
&StakeHistory::default(),
|
||||||
&mut [to_keyed_account],
|
&signers,
|
||||||
),
|
),
|
||||||
Err(InstructionError::InvalidAccountData)
|
Err(InstructionError::InvalidAccountData)
|
||||||
);
|
);
|
||||||
|
@ -1446,31 +1451,37 @@ mod tests {
|
||||||
|
|
||||||
let to = Pubkey::new_rand();
|
let to = Pubkey::new_rand();
|
||||||
let mut to_account = Account::new(1, 0, &system_program::id());
|
let mut to_account = Account::new(1, 0, &system_program::id());
|
||||||
let to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
||||||
|
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
||||||
|
|
||||||
let mut clock = sysvar::clock::Clock::default();
|
let mut clock = sysvar::clock::Clock::default();
|
||||||
|
|
||||||
|
let signers = vec![stake_pubkey].into_iter().collect();
|
||||||
|
|
||||||
// lockup is still in force, can't withdraw
|
// lockup is still in force, can't withdraw
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.withdraw(
|
stake_keyed_account.withdraw(
|
||||||
total_lamports,
|
total_lamports,
|
||||||
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default(),
|
&StakeHistory::default(),
|
||||||
&mut [to_keyed_account],
|
&signers,
|
||||||
),
|
),
|
||||||
Err(StakeError::LockupInForce.into())
|
Err(StakeError::LockupInForce.into())
|
||||||
);
|
);
|
||||||
|
|
||||||
// but we *can* send to the custodian
|
// but we *can* send to the custodian
|
||||||
let mut custodian_account = Account::new(1, 0, &system_program::id());
|
let mut custodian_account = Account::new(1, 0, &system_program::id());
|
||||||
let custodian_keyed_account = KeyedAccount::new(&custodian, false, &mut custodian_account);
|
let mut custodian_keyed_account =
|
||||||
|
KeyedAccount::new(&custodian, false, &mut custodian_account);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.withdraw(
|
stake_keyed_account.withdraw(
|
||||||
total_lamports,
|
total_lamports,
|
||||||
|
&mut custodian_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default(),
|
&StakeHistory::default(),
|
||||||
&mut [custodian_keyed_account],
|
&signers,
|
||||||
),
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
@ -1478,14 +1489,15 @@ mod tests {
|
||||||
stake_keyed_account.account.lamports = total_lamports;
|
stake_keyed_account.account.lamports = total_lamports;
|
||||||
|
|
||||||
// lockup has expired
|
// lockup has expired
|
||||||
let to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
||||||
clock.slot += 1;
|
clock.slot += 1;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.withdraw(
|
stake_keyed_account.withdraw(
|
||||||
total_lamports,
|
total_lamports,
|
||||||
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default(),
|
&StakeHistory::default(),
|
||||||
&mut [to_keyed_account],
|
&signers,
|
||||||
),
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
@ -1609,10 +1621,10 @@ mod tests {
|
||||||
),
|
),
|
||||||
Err(InstructionError::InvalidAccountData)
|
Err(InstructionError::InvalidAccountData)
|
||||||
);
|
);
|
||||||
|
let signers = vec![stake_pubkey].into_iter().collect();
|
||||||
// delegate the stake
|
// delegate the stake
|
||||||
assert!(stake_keyed_account
|
assert!(stake_keyed_account
|
||||||
.delegate_stake(&vote_keyed_account, &clock, &Config::default(), &[])
|
.delegate_stake(&vote_keyed_account, &clock, &Config::default(), &signers)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
|
||||||
let stake_history = create_stake_history_from_stakes(
|
let stake_history = create_stake_history_from_stakes(
|
||||||
|
@ -1725,18 +1737,19 @@ mod tests {
|
||||||
|
|
||||||
let to = Pubkey::new_rand();
|
let to = Pubkey::new_rand();
|
||||||
let mut to_account = Account::new(1, 0, &system_program::id());
|
let mut to_account = Account::new(1, 0, &system_program::id());
|
||||||
let to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
||||||
|
|
||||||
let clock = sysvar::clock::Clock::default();
|
let clock = sysvar::clock::Clock::default();
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
||||||
|
|
||||||
let stake_pubkey0 = Pubkey::new_rand();
|
let stake_pubkey0 = Pubkey::new_rand();
|
||||||
|
let signers = vec![stake_pubkey].into_iter().collect();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.authorize(&stake_pubkey0, StakeAuthorize::Staker, &[]),
|
stake_keyed_account.authorize(&stake_pubkey0, StakeAuthorize::Staker, &signers),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.authorize(&stake_pubkey0, StakeAuthorize::Withdrawer, &[]),
|
stake_keyed_account.authorize(&stake_pubkey0, StakeAuthorize::Withdrawer, &signers),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
if let StakeState::Initialized(authorized, _lockup) =
|
if let StakeState::Initialized(authorized, _lockup) =
|
||||||
|
@ -1751,21 +1764,16 @@ mod tests {
|
||||||
// A second authorization signed by the stake_keyed_account should fail
|
// A second authorization signed by the stake_keyed_account should fail
|
||||||
let stake_pubkey1 = Pubkey::new_rand();
|
let stake_pubkey1 = Pubkey::new_rand();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.authorize(&stake_pubkey1, StakeAuthorize::Staker, &[]),
|
stake_keyed_account.authorize(&stake_pubkey1, StakeAuthorize::Staker, &signers),
|
||||||
Err(InstructionError::MissingRequiredSignature)
|
Err(InstructionError::MissingRequiredSignature)
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut staker_account0 = Account::new(1, 0, &system_program::id());
|
let signers0 = vec![stake_pubkey0].into_iter().collect();
|
||||||
let staker_keyed_account0 = KeyedAccount::new(&stake_pubkey0, true, &mut staker_account0);
|
|
||||||
|
|
||||||
// Test a second authorization by the newly authorized pubkey
|
// Test a second authorization by the newly authorized pubkey
|
||||||
let stake_pubkey2 = Pubkey::new_rand();
|
let stake_pubkey2 = Pubkey::new_rand();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.authorize(
|
stake_keyed_account.authorize(&stake_pubkey2, StakeAuthorize::Staker, &signers0),
|
||||||
&stake_pubkey2,
|
|
||||||
StakeAuthorize::Staker,
|
|
||||||
&[staker_keyed_account0]
|
|
||||||
),
|
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
if let StakeState::Initialized(authorized, _lockup) =
|
if let StakeState::Initialized(authorized, _lockup) =
|
||||||
|
@ -1774,13 +1782,8 @@ mod tests {
|
||||||
assert_eq!(authorized.staker, stake_pubkey2);
|
assert_eq!(authorized.staker, stake_pubkey2);
|
||||||
}
|
}
|
||||||
|
|
||||||
let staker_keyed_account0 = KeyedAccount::new(&stake_pubkey0, true, &mut staker_account0);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.authorize(
|
stake_keyed_account.authorize(&stake_pubkey2, StakeAuthorize::Withdrawer, &signers0,),
|
||||||
&stake_pubkey2,
|
|
||||||
StakeAuthorize::Withdrawer,
|
|
||||||
&[staker_keyed_account0]
|
|
||||||
),
|
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
if let StakeState::Initialized(authorized, _lockup) =
|
if let StakeState::Initialized(authorized, _lockup) =
|
||||||
|
@ -1789,28 +1792,29 @@ mod tests {
|
||||||
assert_eq!(authorized.staker, stake_pubkey2);
|
assert_eq!(authorized.staker, stake_pubkey2);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut staker_account2 = Account::new(1, 0, &system_program::id());
|
let signers2 = vec![stake_pubkey2].into_iter().collect();
|
||||||
let staker_keyed_account2 = KeyedAccount::new(&stake_pubkey2, true, &mut staker_account2);
|
|
||||||
|
|
||||||
// Test that withdrawal to account fails without authorized withdrawer
|
// Test that withdrawal to account fails without authorized withdrawer
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.withdraw(
|
stake_keyed_account.withdraw(
|
||||||
stake_lamports,
|
stake_lamports,
|
||||||
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default(),
|
&StakeHistory::default(),
|
||||||
&mut [to_keyed_account],
|
&signers, // old signer
|
||||||
),
|
),
|
||||||
Err(InstructionError::MissingRequiredSignature)
|
Err(InstructionError::MissingRequiredSignature)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test a successful action by the currently authorized withdrawer
|
// Test a successful action by the currently authorized withdrawer
|
||||||
let to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.withdraw(
|
stake_keyed_account.withdraw(
|
||||||
stake_lamports,
|
stake_lamports,
|
||||||
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default(),
|
&StakeHistory::default(),
|
||||||
&mut [to_keyed_account, staker_keyed_account2],
|
&signers2,
|
||||||
),
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
@ -1836,21 +1840,21 @@ mod tests {
|
||||||
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &mut vote_account);
|
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &mut vote_account);
|
||||||
|
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
||||||
|
let signers = vec![stake_pubkey].into_iter().collect();
|
||||||
stake_keyed_account
|
stake_keyed_account
|
||||||
.delegate_stake(&vote_keyed_account, &clock, &Config::default(), &[])
|
.delegate_stake(&vote_keyed_account, &clock, &Config::default(), &signers)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let new_staker_pubkey = Pubkey::new_rand();
|
let new_staker_pubkey = Pubkey::new_rand();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.authorize(&new_staker_pubkey, StakeAuthorize::Staker, &[]),
|
stake_keyed_account.authorize(&new_staker_pubkey, StakeAuthorize::Staker, &signers),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
let authorized = StakeState::authorized_from(&stake_keyed_account.account).unwrap();
|
let authorized = StakeState::authorized_from(&stake_keyed_account.account).unwrap();
|
||||||
assert_eq!(authorized.staker, new_staker_pubkey);
|
assert_eq!(authorized.staker, new_staker_pubkey);
|
||||||
|
|
||||||
let other_pubkey = Pubkey::new_rand();
|
let other_pubkey = Pubkey::new_rand();
|
||||||
let mut other_account = Account::new(1, 0, &system_program::id());
|
let other_signers = vec![other_pubkey].into_iter().collect();
|
||||||
let other_keyed_account = KeyedAccount::new(&other_pubkey, true, &mut other_account);
|
|
||||||
|
|
||||||
// Use unsigned stake_keyed_account to test other signers
|
// Use unsigned stake_keyed_account to test other signers
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, false, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, false, &mut stake_account);
|
||||||
|
@ -1869,22 +1873,19 @@ mod tests {
|
||||||
&new_vote_keyed_account,
|
&new_vote_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&Config::default(),
|
&Config::default(),
|
||||||
&[other_keyed_account]
|
&other_signers,
|
||||||
),
|
),
|
||||||
Err(InstructionError::MissingRequiredSignature)
|
Err(InstructionError::MissingRequiredSignature)
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut new_staker_account = Account::new(1, 0, &system_program::id());
|
let new_signers = vec![new_staker_pubkey].into_iter().collect();
|
||||||
let new_staker_keyed_account =
|
|
||||||
KeyedAccount::new(&new_staker_pubkey, true, &mut new_staker_account);
|
|
||||||
|
|
||||||
// Authorized staker should succeed
|
// Authorized staker should succeed
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.delegate_stake(
|
stake_keyed_account.delegate_stake(
|
||||||
&new_vote_keyed_account,
|
&new_vote_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&Config::default(),
|
&Config::default(),
|
||||||
&[new_staker_keyed_account]
|
&new_signers
|
||||||
),
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
@ -1892,10 +1893,8 @@ mod tests {
|
||||||
assert_eq!(stake.voter_pubkey(0), &new_voter_pubkey);
|
assert_eq!(stake.voter_pubkey(0), &new_voter_pubkey);
|
||||||
|
|
||||||
// Test another staking action
|
// Test another staking action
|
||||||
let new_staker_keyed_account =
|
|
||||||
KeyedAccount::new(&new_staker_pubkey, true, &mut new_staker_account);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.deactivate_stake(&clock, &[new_staker_keyed_account]),
|
stake_keyed_account.deactivate_stake(&clock, &new_signers),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::hash::Hash;
|
use crate::hash::Hash;
|
||||||
use crate::{clock::Epoch, pubkey::Pubkey};
|
use crate::{clock::Epoch, pubkey::Pubkey};
|
||||||
use std::{cmp, fmt};
|
use std::{cmp, fmt, iter::FromIterator};
|
||||||
|
|
||||||
/// An Account with data that is stored on chain
|
/// An Account with data that is stored on chain
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -196,3 +196,15 @@ pub fn create_keyed_credit_only_accounts(accounts: &mut [(Pubkey, Account)]) ->
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return all the signers from a set of KeyedAccounts
|
||||||
|
pub fn get_signers<A>(keyed_accounts: &[KeyedAccount]) -> A
|
||||||
|
where
|
||||||
|
A: FromIterator<Pubkey>,
|
||||||
|
{
|
||||||
|
keyed_accounts
|
||||||
|
.iter()
|
||||||
|
.filter_map(|keyed_account| keyed_account.signer_key())
|
||||||
|
.cloned()
|
||||||
|
.collect::<A>()
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
use crate::account::KeyedAccount;
|
use crate::{account::KeyedAccount, instruction::InstructionError, pubkey::Pubkey};
|
||||||
use crate::instruction::InstructionError;
|
|
||||||
use crate::pubkey::Pubkey;
|
|
||||||
use num_traits::{FromPrimitive, ToPrimitive};
|
use num_traits::{FromPrimitive, ToPrimitive};
|
||||||
|
|
||||||
// All native programs export a symbol named process()
|
// All native programs export a symbol named process()
|
||||||
|
|
Loading…
Reference in New Issue