Skip to content

Commit

Permalink
Remove possibility to use unitialized split stake account
Browse files Browse the repository at this point in the history
  • Loading branch information
Leo-sol-dev authored and Rabnail committed May 22, 2023
1 parent 531b33c commit 64e4290
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 264 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion programs/marinade-finance/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,3 @@ overflow-checks = true
[dependencies]
anchor-lang = "0.27.0"
anchor-spl = { version = "0.27.0", default-features = false, features = ["stake", "mint", "spl-token", "token"] }
bincode = "1.3.3"
157 changes: 39 additions & 118 deletions programs/marinade-finance/src/instructions/crank/deactivate_stake.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
use crate::{
checks::check_owner_program,
error::MarinadeError,
state::{stake_system::StakeSystem, validator_system::ValidatorSystem},
State,
};
use std::convert::TryFrom;

use anchor_lang::{prelude::*, solana_program::sysvar::stake_history};
use anchor_lang::solana_program::{
program::{invoke, invoke_signed},
stake::program as stake_program,
stake::{self, state::StakeState},
system_instruction, system_program,
program::invoke_signed, stake, stake::state::StakeState, system_program,
};
use anchor_lang::{prelude::*, solana_program::sysvar::stake_history};
use anchor_spl::stake::{
deactivate_stake as solana_deactivate_stake, withdraw,
DeactivateStake as SolanaDeactivateStake, Stake, StakeAccount, Withdraw,
};
use anchor_spl::stake::{Stake, StakeAccount};

use crate::checks::check_stake_amount_and_validator;

Expand Down Expand Up @@ -59,8 +58,12 @@ pub struct DeactivateStake<'info> {
bump = state.stake_system.stake_deposit_bump_seed
)]
pub stake_deposit_authority: UncheckedAccount<'info>,
#[account(mut)]
pub split_stake_account: Signer<'info>,
#[account(
init,
payer = split_stake_rent_payer,
space = std::mem::size_of::<StakeState>(),
)]
pub split_stake_account: Account<'info, StakeAccount>,
#[account(mut, owner = system_program::ID)]
pub split_stake_rent_payer: Signer<'info>,

Expand Down Expand Up @@ -189,38 +192,21 @@ impl<'info> DeactivateStake<'info> {
]],
)?;

// Return rent reserve of unused split stake account if it is not empty
if self.split_stake_account.owner == &stake::program::ID {
let correct =
match bincode::deserialize(&self.split_stake_account.data.as_ref().borrow()) {
Ok(StakeState::Uninitialized) => true,
_ => {
msg!(
"Split stake {} rent return problem",
self.split_stake_account.key
);
false
}
};
if correct {
invoke(
&stake::instruction::withdraw(
self.split_stake_account.key,
self.split_stake_account.key,
self.split_stake_rent_payer.key,
self.split_stake_account.lamports(),
None,
),
&[
self.stake_program.to_account_info(),
self.split_stake_account.to_account_info(),
self.split_stake_rent_payer.to_account_info(),
self.clock.to_account_info(),
self.stake_history.to_account_info(),
],
)?;
}
}
// Return back the rent reserve of unused split stake account
withdraw(
CpiContext::new(
self.stake_program.to_account_info(),
Withdraw {
stake: self.split_stake_account.to_account_info(),
withdrawer: self.split_stake_account.to_account_info(),
to: self.split_stake_rent_payer.to_account_info(),
clock: self.clock.to_account_info(),
stake_history: self.stake_history.to_account_info(),
},
),
self.split_stake_account.to_account_info().lamports(),
None,
)?;

stake.last_update_delegated_lamports
} else {
Expand Down Expand Up @@ -251,85 +237,24 @@ impl<'info> DeactivateStake<'info> {

msg!(
"Deactivate split {} ({} lamports) from stake {}",
self.split_stake_account.key,
self.split_stake_account.key(),
split_amount,
stake.stake_account
);

self.state.stake_system.add(
&mut self.stake_list.data.as_ref().borrow_mut(),
self.split_stake_account.key,
&self.split_stake_account.key(),
split_amount,
&self.clock,
0, // is_emergency_unstaking? no
)?;

let stake_accout_len = std::mem::size_of::<StakeState>();
if self.split_stake_account.owner == &system_program::ID {
// empty account
invoke(
&system_instruction::create_account(
self.split_stake_rent_payer.key,
self.split_stake_account.key,
self.rent.minimum_balance(stake_accout_len),
stake_accout_len as u64,
&stake_program::ID,
),
&[
self.system_program.to_account_info(),
self.split_stake_rent_payer.to_account_info(),
self.split_stake_account.to_account_info(),
],
)?;
} else {
// ready unitialized stake (needed for testing because solana_program_test does not support system_instruction::create_account)
check_owner_program(
&self.split_stake_account,
&stake::program::ID,
"split_stake_account",
)?;
if self.split_stake_account.data_len() < stake_accout_len {
msg!(
"Split stake account {} must have at least {} bytes (got {})",
self.split_stake_account.key,
stake_accout_len,
self.split_stake_account.data_len()
);
return Err(
Error::from(ProgramError::InvalidAccountData).with_source(source!())
);
}
if !self.rent.is_exempt(
self.split_stake_account.lamports(),
self.split_stake_account.data_len(),
) {
msg!(
"Split stake account {} must be rent-exempt",
self.split_stake_account.key
);
return Err(Error::from(ProgramError::InsufficientFunds).with_source(source!()));
}
match bincode::deserialize(&self.split_stake_account.data.as_ref().borrow())
.map_err(|err| ProgramError::BorshIoError(err.to_string()))?
{
StakeState::Uninitialized => (),
_ => {
msg!(
"Split stake {} must be uninitialized",
self.split_stake_account.key
);
return Err(
Error::from(ProgramError::InvalidAccountData).with_source(source!())
);
}
}
}

let split_instruction = stake::instruction::split(
self.stake_account.to_account_info().key,
self.stake_deposit_authority.key,
split_amount,
self.split_stake_account.key,
&self.split_stake_account.key(),
)
.last()
.unwrap()
Expand All @@ -347,25 +272,21 @@ impl<'info> DeactivateStake<'info> {
StakeSystem::STAKE_DEPOSIT_SEED,
&[self.state.stake_system.stake_deposit_bump_seed],
]],
)?;
)?;

invoke_signed(
&stake::instruction::deactivate_stake(
self.split_stake_account.to_account_info().key,
self.stake_deposit_authority.key,
),
&[
self.stake_program.to_account_info(),
self.split_stake_account.to_account_info(),
self.clock.to_account_info(),
self.stake_deposit_authority.to_account_info(),
],
solana_deactivate_stake(CpiContext::new_with_signer(
self.stake_program.to_account_info(),
SolanaDeactivateStake {
stake: self.split_stake_account.to_account_info(),
staker: self.stake_deposit_authority.to_account_info(),
clock: self.clock.to_account_info(),
},
&[&[
&self.state.key().to_bytes(),
StakeSystem::STAKE_DEPOSIT_SEED,
&[self.state.stake_system.stake_deposit_bump_seed],
]],
)?;
))?;

stake.last_update_delegated_lamports -= split_amount;
split_amount
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ use crate::{
};

use anchor_lang::prelude::*;
use anchor_lang::solana_program::{program::invoke_signed, stake};
use anchor_spl::stake::{Stake, StakeAccount};
use anchor_spl::stake::{deactivate_stake, DeactivateStake, Stake, StakeAccount};

#[derive(Accounts)]
pub struct EmergencyUnstake<'info> {
Expand Down Expand Up @@ -78,23 +77,19 @@ impl<'info> EmergencyUnstake<'info> {

let unstake_amount = stake.last_update_delegated_lamports;
msg!("Deactivate whole stake {}", stake.stake_account);
invoke_signed(
&stake::instruction::deactivate_stake(
self.stake_account.to_account_info().key,
self.stake_deposit_authority.key,
),
&[
self.stake_program.to_account_info(),
self.stake_account.to_account_info(),
self.clock.to_account_info(),
self.stake_deposit_authority.to_account_info(),
],
deactivate_stake(CpiContext::new_with_signer(
self.stake_program.to_account_info(),
DeactivateStake {
stake: self.stake_account.to_account_info(),
staker: self.stake_deposit_authority.to_account_info(),
clock: self.clock.to_account_info(),
},
&[&[
&self.state.key().to_bytes(),
StakeSystem::STAKE_DEPOSIT_SEED,
&[self.state.stake_system.stake_deposit_bump_seed],
]],
)?;
))?;

// check the account is not already in emergency_unstake
if stake.is_emergency_unstaking != 0 {
Expand Down
Loading

0 comments on commit 64e4290

Please sign in to comment.