reestablish parameter semantics for withdraw (#6330)

This commit is contained in:
Rob Walker 2019-10-14 15:02:24 -07:00 committed by GitHub
parent 3313b2ff58
commit c2ebf466fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 198 additions and 219 deletions

View File

@ -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),
); );
} }

View File

@ -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(())
); );
} }

View File

@ -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>()
}

View File

@ -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()