Add authorize_staker functionality (#5880)
* Add authorized_staker functionality * Generalize authorize names; implement for Lockup * Fix authorize() usage and improve tests
This commit is contained in:
parent
8f5a1535af
commit
5dceeec1ca
@ -45,7 +45,11 @@ pub enum StakeInstruction {
|
|||||||
/// will allow withdrawal from the stake account.
|
/// will allow withdrawal from the stake account.
|
||||||
///
|
///
|
||||||
Lockup(Slot),
|
Lockup(Slot),
|
||||||
|
/// Authorize a system account to manage stake
|
||||||
|
///
|
||||||
|
/// Expects 1 Account:
|
||||||
|
/// 0 - Locked-up or delegated StakeAccount to be updated with authorized staker
|
||||||
|
Authorize(Pubkey),
|
||||||
/// `Delegate` a stake to a particular vote account
|
/// `Delegate` a stake to a particular vote account
|
||||||
///
|
///
|
||||||
/// Expects 4 Accounts:
|
/// Expects 4 Accounts:
|
||||||
@ -133,6 +137,42 @@ pub fn create_stake_account_and_delegate_stake(
|
|||||||
instructions
|
instructions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn metas_for_authorized_staker(
|
||||||
|
stake_pubkey: &Pubkey,
|
||||||
|
authorized_pubkey: &Pubkey, // currently authorized
|
||||||
|
other_params: &[AccountMeta],
|
||||||
|
) -> Vec<AccountMeta> {
|
||||||
|
let is_own_signer = authorized_pubkey == stake_pubkey;
|
||||||
|
|
||||||
|
// stake account
|
||||||
|
let mut account_metas = vec![AccountMeta::new(*stake_pubkey, is_own_signer)];
|
||||||
|
|
||||||
|
for meta in other_params {
|
||||||
|
account_metas.push(meta.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// append signer at the end
|
||||||
|
if !is_own_signer {
|
||||||
|
account_metas.push(AccountMeta::new_credit_only(*authorized_pubkey, true)) // signer
|
||||||
|
}
|
||||||
|
|
||||||
|
account_metas
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn authorize(
|
||||||
|
stake_pubkey: &Pubkey,
|
||||||
|
authorized_pubkey: &Pubkey,
|
||||||
|
new_authorized_pubkey: &Pubkey,
|
||||||
|
) -> Instruction {
|
||||||
|
let account_metas = metas_for_authorized_staker(stake_pubkey, authorized_pubkey, &[]);
|
||||||
|
|
||||||
|
Instruction::new(
|
||||||
|
id(),
|
||||||
|
&StakeInstruction::Authorize(*new_authorized_pubkey),
|
||||||
|
account_metas,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn redeem_vote_credits(stake_pubkey: &Pubkey, vote_pubkey: &Pubkey) -> Instruction {
|
pub fn redeem_vote_credits(stake_pubkey: &Pubkey, vote_pubkey: &Pubkey) -> Instruction {
|
||||||
let account_metas = vec![
|
let account_metas = vec![
|
||||||
AccountMeta::new(*stake_pubkey, false),
|
AccountMeta::new(*stake_pubkey, false),
|
||||||
@ -193,8 +233,9 @@ pub fn process_instruction(
|
|||||||
// 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::Lockup(slot) => me.lockup(slot),
|
StakeInstruction::Lockup(slot) => me.lockup(slot),
|
||||||
|
StakeInstruction::Authorize(authorized_pubkey) => me.authorize(&authorized_pubkey, &rest),
|
||||||
StakeInstruction::DelegateStake => {
|
StakeInstruction::DelegateStake => {
|
||||||
if rest.len() != 3 {
|
if rest.len() < 3 {
|
||||||
Err(InstructionError::InvalidInstructionData)?;
|
Err(InstructionError::InvalidInstructionData)?;
|
||||||
}
|
}
|
||||||
let vote = &rest[0];
|
let vote = &rest[0];
|
||||||
@ -203,6 +244,7 @@ pub fn process_instruction(
|
|||||||
vote,
|
vote,
|
||||||
&sysvar::clock::from_keyed_account(&rest[1])?,
|
&sysvar::clock::from_keyed_account(&rest[1])?,
|
||||||
&config::from_keyed_account(&rest[2])?,
|
&config::from_keyed_account(&rest[2])?,
|
||||||
|
&rest[3..],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
StakeInstruction::RedeemVoteCredits => {
|
StakeInstruction::RedeemVoteCredits => {
|
||||||
@ -222,28 +264,32 @@ pub fn process_instruction(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
StakeInstruction::Withdraw(lamports) => {
|
StakeInstruction::Withdraw(lamports) => {
|
||||||
if rest.len() != 3 {
|
if rest.len() < 3 {
|
||||||
Err(InstructionError::InvalidInstructionData)?;
|
Err(InstructionError::InvalidInstructionData)?;
|
||||||
}
|
}
|
||||||
let (to, sysvar) = &mut rest.split_at_mut(1);
|
let (to, rest) = &mut rest.split_at_mut(1);
|
||||||
let mut to = &mut to[0];
|
let mut to = &mut to[0];
|
||||||
|
|
||||||
me.withdraw(
|
me.withdraw(
|
||||||
lamports,
|
lamports,
|
||||||
&mut to,
|
&mut to,
|
||||||
&sysvar::clock::from_keyed_account(&sysvar[0])?,
|
&sysvar::clock::from_keyed_account(&rest[0])?,
|
||||||
&sysvar::stake_history::from_keyed_account(&sysvar[1])?,
|
&sysvar::stake_history::from_keyed_account(&rest[1])?,
|
||||||
|
&rest[2..],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
StakeInstruction::Deactivate => {
|
StakeInstruction::Deactivate => {
|
||||||
if rest.len() != 2 {
|
if rest.len() < 2 {
|
||||||
Err(InstructionError::InvalidInstructionData)?;
|
Err(InstructionError::InvalidInstructionData)?;
|
||||||
}
|
}
|
||||||
let (vote, rest) = rest.split_at_mut(1);
|
let (vote, rest) = rest.split_at_mut(1);
|
||||||
let vote = &mut vote[0];
|
let vote = &mut vote[0];
|
||||||
let clock = &rest[0];
|
|
||||||
|
|
||||||
me.deactivate_stake(vote, &sysvar::clock::from_keyed_account(&clock)?)
|
me.deactivate_stake(
|
||||||
|
vote,
|
||||||
|
&sysvar::clock::from_keyed_account(&rest[0])?,
|
||||||
|
&rest[1..],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ use solana_vote_api::vote_state::VoteState;
|
|||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
pub enum StakeState {
|
pub enum StakeState {
|
||||||
Uninitialized,
|
Uninitialized,
|
||||||
Lockup(Slot),
|
Lockup(Lockup),
|
||||||
Stake(Stake),
|
Stake(Stake),
|
||||||
RewardsPool,
|
RewardsPool,
|
||||||
}
|
}
|
||||||
@ -51,8 +51,18 @@ impl StakeState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||||
|
pub struct Lockup {
|
||||||
|
/// slot height at which this stake will allow withdrawal
|
||||||
|
pub slot: Slot,
|
||||||
|
/// alternate signer that is enabled to act on the Stake account after lockup
|
||||||
|
pub authorized_pubkey: Pubkey,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||||
pub struct Stake {
|
pub struct Stake {
|
||||||
|
/// alternate signer that is enabled to act on the Stake account
|
||||||
|
pub authorized_pubkey: Pubkey,
|
||||||
/// most recently delegated vote account pubkey
|
/// most recently delegated vote account pubkey
|
||||||
pub voter_pubkey: Pubkey,
|
pub voter_pubkey: Pubkey,
|
||||||
/// the epoch when voter_pubkey was most recently set
|
/// the epoch when voter_pubkey was most recently set
|
||||||
@ -81,6 +91,7 @@ const MAX_PRIOR_DELEGATES: usize = 32; // this is how many epochs a stake is exp
|
|||||||
impl Default for Stake {
|
impl Default for Stake {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
authorized_pubkey: Pubkey::default(),
|
||||||
voter_pubkey: Pubkey::default(),
|
voter_pubkey: Pubkey::default(),
|
||||||
voter_pubkey_epoch: 0,
|
voter_pubkey_epoch: 0,
|
||||||
credits_observed: 0,
|
credits_observed: 0,
|
||||||
@ -286,6 +297,7 @@ impl Stake {
|
|||||||
fn new_bootstrap(stake: u64, voter_pubkey: &Pubkey, vote_state: &VoteState) -> Self {
|
fn new_bootstrap(stake: u64, voter_pubkey: &Pubkey, vote_state: &VoteState) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
stake,
|
stake,
|
||||||
|
&Pubkey::default(),
|
||||||
voter_pubkey,
|
voter_pubkey,
|
||||||
vote_state,
|
vote_state,
|
||||||
std::u64::MAX,
|
std::u64::MAX,
|
||||||
@ -316,6 +328,7 @@ impl Stake {
|
|||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
stake: u64,
|
stake: u64,
|
||||||
|
stake_pubkey: &Pubkey,
|
||||||
voter_pubkey: &Pubkey,
|
voter_pubkey: &Pubkey,
|
||||||
vote_state: &VoteState,
|
vote_state: &VoteState,
|
||||||
activation_epoch: Epoch,
|
activation_epoch: Epoch,
|
||||||
@ -325,6 +338,7 @@ impl Stake {
|
|||||||
Self {
|
Self {
|
||||||
stake,
|
stake,
|
||||||
activation_epoch,
|
activation_epoch,
|
||||||
|
authorized_pubkey: *stake_pubkey,
|
||||||
voter_pubkey: *voter_pubkey,
|
voter_pubkey: *voter_pubkey,
|
||||||
voter_pubkey_epoch: activation_epoch,
|
voter_pubkey_epoch: activation_epoch,
|
||||||
credits_observed: vote_state.credits(),
|
credits_observed: vote_state.credits(),
|
||||||
@ -339,18 +353,69 @@ impl Stake {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait Authorized {
|
||||||
|
fn check_authorized(
|
||||||
|
&self,
|
||||||
|
stake_pubkey_signer: Option<&Pubkey>,
|
||||||
|
other_signers: &[KeyedAccount],
|
||||||
|
) -> Result<(), InstructionError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Authorized for Lockup {
|
||||||
|
fn check_authorized(
|
||||||
|
&self,
|
||||||
|
stake_pubkey_signer: Option<&Pubkey>,
|
||||||
|
other_signers: &[KeyedAccount],
|
||||||
|
) -> Result<(), InstructionError> {
|
||||||
|
let authorized = Some(&self.authorized_pubkey);
|
||||||
|
if stake_pubkey_signer != authorized
|
||||||
|
&& other_signers
|
||||||
|
.iter()
|
||||||
|
.all(|account| account.signer_key() != authorized)
|
||||||
|
{
|
||||||
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Authorized for Stake {
|
||||||
|
fn check_authorized(
|
||||||
|
&self,
|
||||||
|
stake_pubkey_signer: Option<&Pubkey>,
|
||||||
|
other_signers: &[KeyedAccount],
|
||||||
|
) -> Result<(), InstructionError> {
|
||||||
|
let authorized = Some(&self.authorized_pubkey);
|
||||||
|
if stake_pubkey_signer != authorized
|
||||||
|
&& other_signers
|
||||||
|
.iter()
|
||||||
|
.all(|account| account.signer_key() != authorized)
|
||||||
|
{
|
||||||
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait StakeAccount {
|
pub trait StakeAccount {
|
||||||
fn lockup(&mut self, slot: Slot) -> Result<(), InstructionError>;
|
fn lockup(&mut self, slot: Slot) -> Result<(), InstructionError>;
|
||||||
|
fn authorize(
|
||||||
|
&mut self,
|
||||||
|
authorized_pubkey: &Pubkey,
|
||||||
|
other_signers: &[KeyedAccount],
|
||||||
|
) -> 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],
|
||||||
) -> Result<(), InstructionError>;
|
) -> Result<(), InstructionError>;
|
||||||
fn deactivate_stake(
|
fn deactivate_stake(
|
||||||
&mut self,
|
&mut self,
|
||||||
vote_account: &KeyedAccount,
|
vote_account: &KeyedAccount,
|
||||||
clock: &sysvar::clock::Clock,
|
clock: &sysvar::clock::Clock,
|
||||||
|
other_signers: &[KeyedAccount],
|
||||||
) -> Result<(), InstructionError>;
|
) -> Result<(), InstructionError>;
|
||||||
fn redeem_vote_credits(
|
fn redeem_vote_credits(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -365,12 +430,37 @@ pub trait StakeAccount {
|
|||||||
to: &mut KeyedAccount,
|
to: &mut KeyedAccount,
|
||||||
clock: &sysvar::clock::Clock,
|
clock: &sysvar::clock::Clock,
|
||||||
stake_history: &sysvar::stake_history::StakeHistory,
|
stake_history: &sysvar::stake_history::StakeHistory,
|
||||||
|
other_signers: &[KeyedAccount],
|
||||||
) -> Result<(), InstructionError>;
|
) -> Result<(), InstructionError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> StakeAccount for KeyedAccount<'a> {
|
impl<'a> StakeAccount for KeyedAccount<'a> {
|
||||||
fn lockup(&mut self, lockup: Slot) -> Result<(), InstructionError> {
|
fn lockup(&mut self, lockup: Slot) -> Result<(), InstructionError> {
|
||||||
if let StakeState::Uninitialized = self.state()? {
|
if let StakeState::Uninitialized = self.state()? {
|
||||||
|
self.set_state(&StakeState::Lockup(Lockup {
|
||||||
|
slot: lockup,
|
||||||
|
authorized_pubkey: *self.unsigned_key(),
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
Err(InstructionError::InvalidAccountData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Authorize the given pubkey to manage stake (deactivate, withdraw). This may be called
|
||||||
|
/// multiple times, but will implicitly withdraw authorization from the previously authorized
|
||||||
|
/// staker. The default staker is the owner of the stake account's pubkey.
|
||||||
|
fn authorize(
|
||||||
|
&mut self,
|
||||||
|
authorized_pubkey: &Pubkey,
|
||||||
|
other_signers: &[KeyedAccount],
|
||||||
|
) -> Result<(), InstructionError> {
|
||||||
|
let stake_state = self.state()?;
|
||||||
|
if let StakeState::Stake(mut stake) = stake_state {
|
||||||
|
stake.check_authorized(self.signer_key(), other_signers)?;
|
||||||
|
stake.authorized_pubkey = *authorized_pubkey;
|
||||||
|
self.set_state(&StakeState::Stake(stake))
|
||||||
|
} else if let StakeState::Lockup(mut lockup) = stake_state {
|
||||||
|
lockup.check_authorized(self.signer_key(), other_signers)?;
|
||||||
|
lockup.authorized_pubkey = *authorized_pubkey;
|
||||||
self.set_state(&StakeState::Lockup(lockup))
|
self.set_state(&StakeState::Lockup(lockup))
|
||||||
} else {
|
} else {
|
||||||
Err(InstructionError::InvalidAccountData)
|
Err(InstructionError::InvalidAccountData)
|
||||||
@ -381,23 +471,23 @@ 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],
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
if self.signer_key().is_none() {
|
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let StakeState::Lockup(lockup) = self.state()? {
|
if let StakeState::Lockup(lockup) = self.state()? {
|
||||||
|
lockup.check_authorized(self.signer_key(), other_signers)?;
|
||||||
let stake = Stake::new(
|
let stake = Stake::new(
|
||||||
self.account.lamports,
|
self.account.lamports,
|
||||||
|
&lockup.authorized_pubkey,
|
||||||
vote_account.unsigned_key(),
|
vote_account.unsigned_key(),
|
||||||
&vote_account.state()?,
|
&vote_account.state()?,
|
||||||
clock.epoch,
|
clock.epoch,
|
||||||
config,
|
config,
|
||||||
lockup,
|
lockup.slot,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.set_state(&StakeState::Stake(stake))
|
self.set_state(&StakeState::Stake(stake))
|
||||||
} else if let StakeState::Stake(mut stake) = self.state()? {
|
} else if let StakeState::Stake(mut stake) = self.state()? {
|
||||||
|
stake.check_authorized(self.signer_key(), other_signers)?;
|
||||||
stake.redelegate(
|
stake.redelegate(
|
||||||
vote_account.unsigned_key(),
|
vote_account.unsigned_key(),
|
||||||
&vote_account.state()?,
|
&vote_account.state()?,
|
||||||
@ -412,12 +502,10 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
_vote_account: &KeyedAccount, // TODO: used in slashing
|
_vote_account: &KeyedAccount, // TODO: used in slashing
|
||||||
clock: &sysvar::clock::Clock,
|
clock: &sysvar::clock::Clock,
|
||||||
|
other_signers: &[KeyedAccount],
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
if self.signer_key().is_none() {
|
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let StakeState::Stake(mut stake) = self.state()? {
|
if let StakeState::Stake(mut stake) = self.state()? {
|
||||||
|
stake.check_authorized(self.signer_key(), other_signers)?;
|
||||||
stake.deactivate(clock.epoch);
|
stake.deactivate(clock.epoch);
|
||||||
|
|
||||||
self.set_state(&StakeState::Stake(stake))
|
self.set_state(&StakeState::Stake(stake))
|
||||||
@ -475,11 +563,8 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
|||||||
to: &mut KeyedAccount,
|
to: &mut KeyedAccount,
|
||||||
clock: &sysvar::clock::Clock,
|
clock: &sysvar::clock::Clock,
|
||||||
stake_history: &sysvar::stake_history::StakeHistory,
|
stake_history: &sysvar::stake_history::StakeHistory,
|
||||||
|
other_signers: &[KeyedAccount],
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
if self.signer_key().is_none() {
|
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transfer(
|
fn transfer(
|
||||||
from: &mut Account,
|
from: &mut Account,
|
||||||
to: &mut Account,
|
to: &mut Account,
|
||||||
@ -495,6 +580,7 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
|||||||
|
|
||||||
match self.state()? {
|
match self.state()? {
|
||||||
StakeState::Stake(stake) => {
|
StakeState::Stake(stake) => {
|
||||||
|
stake.check_authorized(self.signer_key(), other_signers)?;
|
||||||
// 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))
|
||||||
@ -510,11 +596,16 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
StakeState::Lockup(lockup) => {
|
StakeState::Lockup(lockup) => {
|
||||||
if lockup > clock.slot {
|
lockup.check_authorized(self.signer_key(), other_signers)?;
|
||||||
|
if lockup.slot > clock.slot {
|
||||||
return Err(InstructionError::InsufficientFunds);
|
return Err(InstructionError::InsufficientFunds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StakeState::Uninitialized => {}
|
StakeState::Uninitialized => {
|
||||||
|
if self.signer_key().is_none() {
|
||||||
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => return Err(InstructionError::InvalidAccountData),
|
_ => return Err(InstructionError::InvalidAccountData),
|
||||||
}
|
}
|
||||||
transfer(&mut self.account, &mut to.account, lamports)
|
transfer(&mut self.account, &mut to.account, lamports)
|
||||||
@ -623,7 +714,10 @@ mod tests {
|
|||||||
let stake_lamports = 42;
|
let stake_lamports = 42;
|
||||||
let mut stake_account = Account::new_data_with_space(
|
let mut stake_account = Account::new_data_with_space(
|
||||||
stake_lamports,
|
stake_lamports,
|
||||||
&StakeState::Lockup(0),
|
&StakeState::Lockup(Lockup {
|
||||||
|
slot: 0,
|
||||||
|
authorized_pubkey: stake_pubkey,
|
||||||
|
}),
|
||||||
std::mem::size_of::<StakeState>(),
|
std::mem::size_of::<StakeState>(),
|
||||||
&id(),
|
&id(),
|
||||||
)
|
)
|
||||||
@ -634,18 +728,29 @@ mod tests {
|
|||||||
|
|
||||||
{
|
{
|
||||||
let stake_state: StakeState = stake_keyed_account.state().unwrap();
|
let stake_state: StakeState = stake_keyed_account.state().unwrap();
|
||||||
assert_eq!(stake_state, StakeState::Lockup(0));
|
assert_eq!(
|
||||||
|
stake_state,
|
||||||
|
StakeState::Lockup(Lockup {
|
||||||
|
slot: 0,
|
||||||
|
authorized_pubkey: stake_pubkey
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.delegate_stake(&vote_keyed_account, &clock, &Config::default()),
|
stake_keyed_account.delegate_stake(
|
||||||
|
&vote_keyed_account,
|
||||||
|
&clock,
|
||||||
|
&Config::default(),
|
||||||
|
&[]
|
||||||
|
),
|
||||||
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);
|
||||||
assert!(stake_keyed_account
|
assert!(stake_keyed_account
|
||||||
.delegate_stake(&vote_keyed_account, &clock, &Config::default())
|
.delegate_stake(&vote_keyed_account, &clock, &Config::default(), &[])
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
|
||||||
// verify that delegate_stake() looks right, compare against hand-rolled
|
// verify that delegate_stake() looks right, compare against hand-rolled
|
||||||
@ -653,6 +758,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake,
|
stake,
|
||||||
Stake {
|
Stake {
|
||||||
|
authorized_pubkey: stake_pubkey,
|
||||||
voter_pubkey: vote_pubkey,
|
voter_pubkey: vote_pubkey,
|
||||||
voter_pubkey_epoch: clock.epoch,
|
voter_pubkey_epoch: clock.epoch,
|
||||||
credits_observed: vote_state.credits(),
|
credits_observed: vote_state.credits(),
|
||||||
@ -670,7 +776,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(), &[])
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
|
||||||
// verify that non-stakes fail delegate_stake()
|
// verify that non-stakes fail delegate_stake()
|
||||||
@ -678,7 +784,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(), &[])
|
||||||
.is_err());
|
.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -980,7 +1086,10 @@ mod tests {
|
|||||||
// first time works, as is uninit
|
// first time works, as is uninit
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
StakeState::from(&stake_keyed_account.account).unwrap(),
|
StakeState::from(&stake_keyed_account.account).unwrap(),
|
||||||
StakeState::Lockup(1)
|
StakeState::Lockup(Lockup {
|
||||||
|
slot: 1,
|
||||||
|
authorized_pubkey: stake_pubkey
|
||||||
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// 2nd time fails, can't move it from anything other than uninit->lockup
|
// 2nd time fails, can't move it from anything other than uninit->lockup
|
||||||
@ -996,7 +1105,10 @@ mod tests {
|
|||||||
let stake_lamports = 42;
|
let stake_lamports = 42;
|
||||||
let mut stake_account = Account::new_data_with_space(
|
let mut stake_account = Account::new_data_with_space(
|
||||||
stake_lamports,
|
stake_lamports,
|
||||||
&StakeState::Lockup(0),
|
&StakeState::Lockup(Lockup {
|
||||||
|
slot: 0,
|
||||||
|
authorized_pubkey: stake_pubkey,
|
||||||
|
}),
|
||||||
std::mem::size_of::<StakeState>(),
|
std::mem::size_of::<StakeState>(),
|
||||||
&id(),
|
&id(),
|
||||||
)
|
)
|
||||||
@ -1012,17 +1124,10 @@ 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 vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &mut vote_account);
|
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &mut vote_account);
|
||||||
|
|
||||||
// unsigned keyed account
|
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, false, &mut stake_account);
|
|
||||||
assert_eq!(
|
|
||||||
stake_keyed_account.deactivate_stake(&vote_keyed_account, &clock),
|
|
||||||
Err(InstructionError::MissingRequiredSignature)
|
|
||||||
);
|
|
||||||
|
|
||||||
// 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);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.deactivate_stake(&vote_keyed_account, &clock),
|
stake_keyed_account.deactivate_stake(&vote_keyed_account, &clock, &[]),
|
||||||
Err(InstructionError::InvalidAccountData)
|
Err(InstructionError::InvalidAccountData)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1033,13 +1138,26 @@ mod tests {
|
|||||||
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();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.delegate_stake(&vote_keyed_account, &clock, &Config::default()),
|
stake_keyed_account.delegate_stake(
|
||||||
|
&vote_keyed_account,
|
||||||
|
&clock,
|
||||||
|
&Config::default(),
|
||||||
|
&[]
|
||||||
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
|
||||||
// Deactivate after staking
|
// unsigned keyed account
|
||||||
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, false, &mut stake_account);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.deactivate_stake(&vote_keyed_account, &clock),
|
stake_keyed_account.deactivate_stake(&vote_keyed_account, &clock, &[]),
|
||||||
|
Err(InstructionError::MissingRequiredSignature)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Deactivate after staking
|
||||||
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
||||||
|
assert_eq!(
|
||||||
|
stake_keyed_account.deactivate_stake(&vote_keyed_account, &clock, &[]),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1050,7 +1168,7 @@ mod tests {
|
|||||||
let stake_lamports = 42;
|
let stake_lamports = 42;
|
||||||
let mut stake_account = Account::new_data_with_space(
|
let mut stake_account = Account::new_data_with_space(
|
||||||
stake_lamports,
|
stake_lamports,
|
||||||
&StakeState::Lockup(0),
|
&StakeState::Uninitialized,
|
||||||
std::mem::size_of::<StakeState>(),
|
std::mem::size_of::<StakeState>(),
|
||||||
&id(),
|
&id(),
|
||||||
)
|
)
|
||||||
@ -1069,7 +1187,8 @@ mod tests {
|
|||||||
stake_lamports,
|
stake_lamports,
|
||||||
&mut to_keyed_account,
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default()
|
&StakeHistory::default(),
|
||||||
|
&[],
|
||||||
),
|
),
|
||||||
Err(InstructionError::MissingRequiredSignature)
|
Err(InstructionError::MissingRequiredSignature)
|
||||||
);
|
);
|
||||||
@ -1081,7 +1200,8 @@ mod tests {
|
|||||||
stake_lamports,
|
stake_lamports,
|
||||||
&mut to_keyed_account,
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default()
|
&StakeHistory::default(),
|
||||||
|
&[],
|
||||||
),
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
@ -1090,14 +1210,19 @@ mod tests {
|
|||||||
// reset balance
|
// reset balance
|
||||||
stake_account.lamports = stake_lamports;
|
stake_account.lamports = stake_lamports;
|
||||||
|
|
||||||
// signed keyed account and uninitialized, more than available should fail
|
// lockup
|
||||||
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
||||||
|
stake_keyed_account.lockup(0).unwrap();
|
||||||
|
|
||||||
|
// 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);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.withdraw(
|
stake_keyed_account.withdraw(
|
||||||
stake_lamports + 1,
|
stake_lamports + 1,
|
||||||
&mut to_keyed_account,
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default()
|
&StakeHistory::default(),
|
||||||
|
&[],
|
||||||
),
|
),
|
||||||
Err(InstructionError::InsufficientFunds)
|
Err(InstructionError::InsufficientFunds)
|
||||||
);
|
);
|
||||||
@ -1109,7 +1234,12 @@ mod tests {
|
|||||||
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();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.delegate_stake(&vote_keyed_account, &clock, &Config::default()),
|
stake_keyed_account.delegate_stake(
|
||||||
|
&vote_keyed_account,
|
||||||
|
&clock,
|
||||||
|
&Config::default(),
|
||||||
|
&[]
|
||||||
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1122,7 +1252,8 @@ mod tests {
|
|||||||
10,
|
10,
|
||||||
&mut to_keyed_account,
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default()
|
&StakeHistory::default(),
|
||||||
|
&[],
|
||||||
),
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
@ -1136,14 +1267,15 @@ mod tests {
|
|||||||
10 + 1,
|
10 + 1,
|
||||||
&mut to_keyed_account,
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default()
|
&StakeHistory::default(),
|
||||||
|
&[],
|
||||||
),
|
),
|
||||||
Err(InstructionError::InsufficientFunds)
|
Err(InstructionError::InsufficientFunds)
|
||||||
);
|
);
|
||||||
|
|
||||||
// deactivate the stake before withdrawal
|
// deactivate the stake before withdrawal
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.deactivate_stake(&vote_keyed_account, &clock),
|
stake_keyed_account.deactivate_stake(&vote_keyed_account, &clock, &[]),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
// simulate time passing
|
// simulate time passing
|
||||||
@ -1155,7 +1287,8 @@ mod tests {
|
|||||||
stake_lamports + 10 + 1,
|
stake_lamports + 10 + 1,
|
||||||
&mut to_keyed_account,
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default()
|
&StakeHistory::default(),
|
||||||
|
&[],
|
||||||
),
|
),
|
||||||
Err(InstructionError::InsufficientFunds)
|
Err(InstructionError::InsufficientFunds)
|
||||||
);
|
);
|
||||||
@ -1166,7 +1299,8 @@ mod tests {
|
|||||||
stake_lamports + 10,
|
stake_lamports + 10,
|
||||||
&mut to_keyed_account,
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default()
|
&StakeHistory::default(),
|
||||||
|
&[],
|
||||||
),
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
@ -1180,7 +1314,10 @@ mod tests {
|
|||||||
let stake_lamports = 42;
|
let stake_lamports = 42;
|
||||||
let mut stake_account = Account::new_data_with_space(
|
let mut stake_account = Account::new_data_with_space(
|
||||||
total_lamports,
|
total_lamports,
|
||||||
&StakeState::Lockup(0),
|
&StakeState::Lockup(Lockup {
|
||||||
|
slot: 0,
|
||||||
|
authorized_pubkey: stake_pubkey,
|
||||||
|
}),
|
||||||
std::mem::size_of::<StakeState>(),
|
std::mem::size_of::<StakeState>(),
|
||||||
&id(),
|
&id(),
|
||||||
)
|
)
|
||||||
@ -1203,7 +1340,12 @@ mod tests {
|
|||||||
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();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.delegate_stake(&vote_keyed_account, &future, &Config::default()),
|
stake_keyed_account.delegate_stake(
|
||||||
|
&vote_keyed_account,
|
||||||
|
&future,
|
||||||
|
&Config::default(),
|
||||||
|
&[]
|
||||||
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1219,7 +1361,8 @@ mod tests {
|
|||||||
total_lamports - stake_lamports + 1,
|
total_lamports - stake_lamports + 1,
|
||||||
&mut to_keyed_account,
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&stake_history
|
&stake_history,
|
||||||
|
&[],
|
||||||
),
|
),
|
||||||
Err(InstructionError::InsufficientFunds)
|
Err(InstructionError::InsufficientFunds)
|
||||||
);
|
);
|
||||||
@ -1247,7 +1390,8 @@ mod tests {
|
|||||||
total_lamports,
|
total_lamports,
|
||||||
&mut to_keyed_account,
|
&mut to_keyed_account,
|
||||||
&sysvar::clock::Clock::default(),
|
&sysvar::clock::Clock::default(),
|
||||||
&StakeHistory::default()
|
&StakeHistory::default(),
|
||||||
|
&[],
|
||||||
),
|
),
|
||||||
Err(InstructionError::InvalidAccountData)
|
Err(InstructionError::InvalidAccountData)
|
||||||
);
|
);
|
||||||
@ -1259,7 +1403,10 @@ mod tests {
|
|||||||
let total_lamports = 100;
|
let total_lamports = 100;
|
||||||
let mut stake_account = Account::new_data_with_space(
|
let mut stake_account = Account::new_data_with_space(
|
||||||
total_lamports,
|
total_lamports,
|
||||||
&StakeState::Lockup(1),
|
&StakeState::Lockup(Lockup {
|
||||||
|
slot: 1,
|
||||||
|
authorized_pubkey: stake_pubkey,
|
||||||
|
}),
|
||||||
std::mem::size_of::<StakeState>(),
|
std::mem::size_of::<StakeState>(),
|
||||||
&id(),
|
&id(),
|
||||||
)
|
)
|
||||||
@ -1277,7 +1424,8 @@ mod tests {
|
|||||||
total_lamports,
|
total_lamports,
|
||||||
&mut to_keyed_account,
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default()
|
&StakeHistory::default(),
|
||||||
|
&[],
|
||||||
),
|
),
|
||||||
Err(InstructionError::InsufficientFunds)
|
Err(InstructionError::InsufficientFunds)
|
||||||
);
|
);
|
||||||
@ -1288,7 +1436,8 @@ mod tests {
|
|||||||
total_lamports,
|
total_lamports,
|
||||||
&mut to_keyed_account,
|
&mut to_keyed_account,
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default()
|
&StakeHistory::default(),
|
||||||
|
&[],
|
||||||
),
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
@ -1385,17 +1534,20 @@ mod tests {
|
|||||||
let mut rewards_pool_keyed_account =
|
let mut rewards_pool_keyed_account =
|
||||||
KeyedAccount::new(&rewards_pool_pubkey, false, &mut rewards_pool_account);
|
KeyedAccount::new(&rewards_pool_pubkey, false, &mut rewards_pool_account);
|
||||||
|
|
||||||
let pubkey = Pubkey::default();
|
let stake_pubkey = Pubkey::default();
|
||||||
let stake_lamports = 100;
|
let stake_lamports = 100;
|
||||||
let mut stake_account = Account::new_data_with_space(
|
let mut stake_account = Account::new_data_with_space(
|
||||||
stake_lamports,
|
stake_lamports,
|
||||||
&StakeState::Lockup(0),
|
&StakeState::Lockup(Lockup {
|
||||||
|
slot: 0,
|
||||||
|
authorized_pubkey: stake_pubkey,
|
||||||
|
}),
|
||||||
std::mem::size_of::<StakeState>(),
|
std::mem::size_of::<StakeState>(),
|
||||||
&id(),
|
&id(),
|
||||||
)
|
)
|
||||||
.expect("stake_account");
|
.expect("stake_account");
|
||||||
|
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&pubkey, true, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
||||||
|
|
||||||
let vote_pubkey = Pubkey::new_rand();
|
let vote_pubkey = Pubkey::new_rand();
|
||||||
let mut vote_account =
|
let mut vote_account =
|
||||||
@ -1415,7 +1567,7 @@ mod tests {
|
|||||||
|
|
||||||
// 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(), &[])
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
|
||||||
let stake_history = create_stake_history_from_stakes(
|
let stake_history = create_stake_history_from_stakes(
|
||||||
@ -1499,4 +1651,160 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_authorize_lockup() {
|
||||||
|
let stake_pubkey = Pubkey::new_rand();
|
||||||
|
let stake_lamports = 42;
|
||||||
|
let mut stake_account = Account::new_data_with_space(
|
||||||
|
stake_lamports,
|
||||||
|
&StakeState::Lockup(Lockup {
|
||||||
|
slot: 0,
|
||||||
|
authorized_pubkey: stake_pubkey,
|
||||||
|
}),
|
||||||
|
std::mem::size_of::<StakeState>(),
|
||||||
|
&id(),
|
||||||
|
)
|
||||||
|
.expect("stake_account");
|
||||||
|
|
||||||
|
let to = Pubkey::new_rand();
|
||||||
|
let mut to_account = Account::new(1, 0, &system_program::id());
|
||||||
|
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
||||||
|
|
||||||
|
let clock = sysvar::clock::Clock::default();
|
||||||
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
||||||
|
|
||||||
|
let stake_pubkey0 = Pubkey::new_rand();
|
||||||
|
assert_eq!(stake_keyed_account.authorize(&stake_pubkey0, &[]), Ok(()));
|
||||||
|
if let StakeState::Lockup(lockup) = StakeState::from(&stake_keyed_account.account).unwrap()
|
||||||
|
{
|
||||||
|
assert_eq!(lockup.authorized_pubkey, stake_pubkey0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A second authorization signed by the stake_keyed_account should fail
|
||||||
|
let stake_pubkey1 = Pubkey::new_rand();
|
||||||
|
assert_eq!(
|
||||||
|
stake_keyed_account.authorize(&stake_pubkey1, &[]),
|
||||||
|
Err(InstructionError::MissingRequiredSignature)
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut staker_account0 = Account::new(1, 0, &system_program::id());
|
||||||
|
let staker_keyed_account0 = KeyedAccount::new(&stake_pubkey0, true, &mut staker_account0);
|
||||||
|
|
||||||
|
// Test a second authorization by the newly authorized pubkey
|
||||||
|
let stake_pubkey2 = Pubkey::new_rand();
|
||||||
|
assert_eq!(
|
||||||
|
stake_keyed_account.authorize(&stake_pubkey2, &[staker_keyed_account0]),
|
||||||
|
Ok(())
|
||||||
|
);
|
||||||
|
if let StakeState::Lockup(lockup) = StakeState::from(&stake_keyed_account.account).unwrap()
|
||||||
|
{
|
||||||
|
assert_eq!(lockup.authorized_pubkey, stake_pubkey2);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut staker_account2 = Account::new(1, 0, &system_program::id());
|
||||||
|
let staker_keyed_account2 = KeyedAccount::new(&stake_pubkey2, true, &mut staker_account2);
|
||||||
|
|
||||||
|
// Test an action by the currently authorized pubkey
|
||||||
|
assert_eq!(
|
||||||
|
stake_keyed_account.withdraw(
|
||||||
|
stake_lamports,
|
||||||
|
&mut to_keyed_account,
|
||||||
|
&clock,
|
||||||
|
&StakeHistory::default(),
|
||||||
|
&[staker_keyed_account2],
|
||||||
|
),
|
||||||
|
Ok(())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_authorize_delegated_stake() {
|
||||||
|
let stake_pubkey = Pubkey::new_rand();
|
||||||
|
let stake_lamports = 42;
|
||||||
|
let mut stake_account = Account::new_data_with_space(
|
||||||
|
stake_lamports,
|
||||||
|
&StakeState::Lockup(Lockup {
|
||||||
|
slot: 0,
|
||||||
|
authorized_pubkey: stake_pubkey,
|
||||||
|
}),
|
||||||
|
std::mem::size_of::<StakeState>(),
|
||||||
|
&id(),
|
||||||
|
)
|
||||||
|
.expect("stake_account");
|
||||||
|
|
||||||
|
let clock = sysvar::clock::Clock::default();
|
||||||
|
|
||||||
|
let vote_pubkey = Pubkey::new_rand();
|
||||||
|
let mut vote_account =
|
||||||
|
vote_state::create_account(&vote_pubkey, &Pubkey::new_rand(), 0, 100);
|
||||||
|
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);
|
||||||
|
stake_keyed_account
|
||||||
|
.delegate_stake(&vote_keyed_account, &clock, &Config::default(), &[])
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let new_staker_pubkey = Pubkey::new_rand();
|
||||||
|
assert_eq!(
|
||||||
|
stake_keyed_account.authorize(&new_staker_pubkey, &[]),
|
||||||
|
Ok(())
|
||||||
|
);
|
||||||
|
let stake = StakeState::stake_from(&stake_keyed_account.account).unwrap();
|
||||||
|
assert_eq!(stake.authorized_pubkey, new_staker_pubkey);
|
||||||
|
|
||||||
|
let other_pubkey = Pubkey::new_rand();
|
||||||
|
let mut other_account = Account::new(1, 0, &system_program::id());
|
||||||
|
let other_keyed_account = KeyedAccount::new(&other_pubkey, true, &mut other_account);
|
||||||
|
|
||||||
|
// Use unsigned stake_keyed_account to test other signers
|
||||||
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, false, &mut stake_account);
|
||||||
|
|
||||||
|
let new_voter_pubkey = Pubkey::new_rand();
|
||||||
|
let vote_state = VoteState::default();
|
||||||
|
let mut new_vote_account =
|
||||||
|
vote_state::create_account(&new_voter_pubkey, &Pubkey::new_rand(), 0, 100);
|
||||||
|
let mut new_vote_keyed_account =
|
||||||
|
KeyedAccount::new(&new_voter_pubkey, false, &mut new_vote_account);
|
||||||
|
new_vote_keyed_account.set_state(&vote_state).unwrap();
|
||||||
|
|
||||||
|
// Random other account should fail
|
||||||
|
assert_eq!(
|
||||||
|
stake_keyed_account.delegate_stake(
|
||||||
|
&new_vote_keyed_account,
|
||||||
|
&clock,
|
||||||
|
&Config::default(),
|
||||||
|
&[other_keyed_account]
|
||||||
|
),
|
||||||
|
Err(InstructionError::MissingRequiredSignature)
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut new_staker_account = Account::new(1, 0, &system_program::id());
|
||||||
|
let new_staker_keyed_account =
|
||||||
|
KeyedAccount::new(&new_staker_pubkey, true, &mut new_staker_account);
|
||||||
|
|
||||||
|
// Authorized staker should succeed
|
||||||
|
assert_eq!(
|
||||||
|
stake_keyed_account.delegate_stake(
|
||||||
|
&new_vote_keyed_account,
|
||||||
|
&clock,
|
||||||
|
&Config::default(),
|
||||||
|
&[new_staker_keyed_account]
|
||||||
|
),
|
||||||
|
Ok(())
|
||||||
|
);
|
||||||
|
let stake = StakeState::stake_from(&stake_keyed_account.account).unwrap();
|
||||||
|
assert_eq!(stake.voter_pubkey(0), &new_voter_pubkey);
|
||||||
|
|
||||||
|
// Test another staking action
|
||||||
|
let new_staker_keyed_account =
|
||||||
|
KeyedAccount::new(&new_staker_pubkey, true, &mut new_staker_account);
|
||||||
|
assert_eq!(
|
||||||
|
stake_keyed_account.deactivate_stake(
|
||||||
|
&vote_keyed_account,
|
||||||
|
&clock,
|
||||||
|
&[new_staker_keyed_account]
|
||||||
|
),
|
||||||
|
Ok(())
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user