Rework create validator stake account (#1539)

This commit is contained in:
Jon Cinque 2021-03-31 00:54:15 +02:00 committed by GitHub
parent f2de73da8e
commit 9f38a6f4b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 447 additions and 640 deletions

View File

@ -277,13 +277,10 @@ fn command_vsa_create(config: &Config, pool: &Pubkey, vote_account: &Pubkey) ->
create_validator_stake_account( create_validator_stake_account(
&spl_stake_pool::id(), &spl_stake_pool::id(),
&pool, &pool,
&config.owner.pubkey(),
&config.fee_payer.pubkey(), &config.fee_payer.pubkey(),
&stake_account, &stake_account,
&vote_account, &vote_account,
&config.owner.pubkey(),
&config.owner.pubkey(),
&solana_program::system_program::id(),
&stake_program_id(),
)?, )?,
], ],
Some(&config.fee_payer.pubkey()), Some(&config.fee_payer.pubkey()),
@ -291,7 +288,10 @@ fn command_vsa_create(config: &Config, pool: &Pubkey, vote_account: &Pubkey) ->
let (recent_blockhash, fee_calculator) = config.rpc_client.get_recent_blockhash()?; let (recent_blockhash, fee_calculator) = config.rpc_client.get_recent_blockhash()?;
check_fee_payer_balance(config, fee_calculator.calculate_fee(&transaction.message()))?; check_fee_payer_balance(config, fee_calculator.calculate_fee(&transaction.message()))?;
transaction.sign(&[config.fee_payer.as_ref()], recent_blockhash); transaction.sign(
&[config.fee_payer.as_ref(), config.owner.as_ref()],
recent_blockhash,
);
send_transaction(&config, transaction)?; send_transaction(&config, transaction)?;
Ok(()) Ok(())
} }
@ -377,7 +377,6 @@ fn command_vsa_add(
&token_receiver, &token_receiver,
&pool_data.pool_mint, &pool_data.pool_mint,
&spl_token::id(), &spl_token::id(),
&stake_program_id(),
)?, )?,
]); ]);
@ -468,7 +467,6 @@ fn command_vsa_remove(
&withdraw_from, &withdraw_from,
&pool_data.pool_mint, &pool_data.pool_mint,
&spl_token::id(), &spl_token::id(),
&stake_program_id(),
)?, )?,
], ],
Some(&config.fee_payer.pubkey()), Some(&config.fee_payer.pubkey()),
@ -645,7 +643,6 @@ fn command_deposit(
&pool_data.owner_fee_account, &pool_data.owner_fee_account,
&pool_data.pool_mint, &pool_data.pool_mint,
&spl_token::id(), &spl_token::id(),
&stake_program_id(),
)?, )?,
]); ]);
@ -984,7 +981,6 @@ fn command_withdraw(
&withdraw_from, &withdraw_from,
&pool_data.pool_mint, &pool_data.pool_mint,
&spl_token::id(), &spl_token::id(),
&stake_program_id(),
withdraw_stake.pool_amount, withdraw_stake.pool_amount,
)?); )?);
} }
@ -1163,7 +1159,7 @@ fn main() {
.help("Max number of validators included in the stake pool"), .help("Max number of validators included in the stake pool"),
) )
) )
.subcommand(SubCommand::with_name("create-validator-stake").about("Create a new stake account to use with the pool") .subcommand(SubCommand::with_name("create-validator-stake").about("Create a new stake account to use with the pool. Must be signed by the pool owner.")
.arg( .arg(
Arg::with_name("pool") Arg::with_name("pool")
.index(1) .index(1)

View File

@ -3,12 +3,13 @@
#![allow(clippy::too_many_arguments)] #![allow(clippy::too_many_arguments)]
use { use {
crate::stake,
borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, borsh::{BorshDeserialize, BorshSchema, BorshSerialize},
solana_program::{ solana_program::{
instruction::{AccountMeta, Instruction}, instruction::{AccountMeta, Instruction},
program_error::ProgramError, program_error::ProgramError,
pubkey::Pubkey, pubkey::Pubkey,
sysvar, system_program, sysvar,
}, },
}; };
@ -48,17 +49,17 @@ pub enum StakePoolInstruction {
/// Creates new program account for accumulating stakes for a particular validator /// Creates new program account for accumulating stakes for a particular validator
/// ///
/// 0. `[]` Stake pool account this stake will belong to /// 0. `[]` Stake pool account this stake will belong to
/// 1. `[ws]` Funding account (must be a system account) /// 1. `[s]` Owner
/// 2. `[w]` Stake account to be created /// 2. `[ws]` Funding account (must be a system account)
/// 3. `[]` Validator this stake account will vote for /// 3. `[w]` Stake account to be created
/// 4. `[]` Stake authority for the new stake account /// 4. `[]` Validator this stake account will vote for
/// 5. `[]` Withdraw authority for the new stake account /// 5. `[]` Rent sysvar
/// 6. `[]` Rent sysvar /// 6. `[]` System program
/// 7. `[]` System program /// 7. `[]` Stake program
/// 8. `[]` Stake program
CreateValidatorStakeAccount, CreateValidatorStakeAccount,
/// Adds validator stake account to the pool /// Adds stake account delegated to validator to the pool's list of
/// managed validators
/// ///
/// 0. `[w]` Stake pool /// 0. `[w]` Stake pool
/// 1. `[s]` Owner /// 1. `[s]` Owner
@ -185,24 +186,23 @@ pub fn initialize(
pub fn create_validator_stake_account( pub fn create_validator_stake_account(
program_id: &Pubkey, program_id: &Pubkey,
stake_pool: &Pubkey, stake_pool: &Pubkey,
owner: &Pubkey,
funder: &Pubkey, funder: &Pubkey,
stake_account: &Pubkey, stake_account: &Pubkey,
validator: &Pubkey, validator: &Pubkey,
stake_authority: &Pubkey,
withdraw_authority: &Pubkey,
system_program_id: &Pubkey,
stake_program_id: &Pubkey,
) -> Result<Instruction, ProgramError> { ) -> Result<Instruction, ProgramError> {
let accounts = vec![ let accounts = vec![
AccountMeta::new_readonly(*stake_pool, false), AccountMeta::new_readonly(*stake_pool, false),
AccountMeta::new_readonly(*owner, true),
AccountMeta::new(*funder, true), AccountMeta::new(*funder, true),
AccountMeta::new(*stake_account, false), AccountMeta::new(*stake_account, false),
AccountMeta::new_readonly(*validator, false), AccountMeta::new_readonly(*validator, false),
AccountMeta::new_readonly(*stake_authority, false),
AccountMeta::new_readonly(*withdraw_authority, false),
AccountMeta::new_readonly(sysvar::rent::id(), false), AccountMeta::new_readonly(sysvar::rent::id(), false),
AccountMeta::new_readonly(*system_program_id, false), AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(*stake_program_id, false), AccountMeta::new_readonly(sysvar::stake_history::id(), false),
AccountMeta::new_readonly(stake::config_id(), false),
AccountMeta::new_readonly(system_program::id(), false),
AccountMeta::new_readonly(stake::id(), false),
]; ];
Ok(Instruction { Ok(Instruction {
program_id: *program_id, program_id: *program_id,
@ -220,10 +220,9 @@ pub fn add_validator_to_pool(
stake_pool_withdraw: &Pubkey, stake_pool_withdraw: &Pubkey,
validator_list: &Pubkey, validator_list: &Pubkey,
stake_account: &Pubkey, stake_account: &Pubkey,
pool_tokens_to: &Pubkey, pool_token_receiver: &Pubkey,
pool_mint: &Pubkey, pool_mint: &Pubkey,
token_program_id: &Pubkey, token_program_id: &Pubkey,
stake_program_id: &Pubkey,
) -> Result<Instruction, ProgramError> { ) -> Result<Instruction, ProgramError> {
let accounts = vec![ let accounts = vec![
AccountMeta::new(*stake_pool, false), AccountMeta::new(*stake_pool, false),
@ -232,12 +231,12 @@ pub fn add_validator_to_pool(
AccountMeta::new_readonly(*stake_pool_withdraw, false), AccountMeta::new_readonly(*stake_pool_withdraw, false),
AccountMeta::new(*validator_list, false), AccountMeta::new(*validator_list, false),
AccountMeta::new(*stake_account, false), AccountMeta::new(*stake_account, false),
AccountMeta::new(*pool_tokens_to, false), AccountMeta::new(*pool_token_receiver, false),
AccountMeta::new(*pool_mint, false), AccountMeta::new(*pool_mint, false),
AccountMeta::new_readonly(sysvar::clock::id(), false), AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(sysvar::stake_history::id(), false), AccountMeta::new_readonly(sysvar::stake_history::id(), false),
AccountMeta::new_readonly(*token_program_id, false), AccountMeta::new_readonly(*token_program_id, false),
AccountMeta::new_readonly(*stake_program_id, false), AccountMeta::new_readonly(stake::id(), false),
]; ];
Ok(Instruction { Ok(Instruction {
program_id: *program_id, program_id: *program_id,
@ -258,7 +257,6 @@ pub fn remove_validator_from_pool(
burn_from: &Pubkey, burn_from: &Pubkey,
pool_mint: &Pubkey, pool_mint: &Pubkey,
token_program_id: &Pubkey, token_program_id: &Pubkey,
stake_program_id: &Pubkey,
) -> Result<Instruction, ProgramError> { ) -> Result<Instruction, ProgramError> {
let accounts = vec![ let accounts = vec![
AccountMeta::new(*stake_pool, false), AccountMeta::new(*stake_pool, false),
@ -271,7 +269,7 @@ pub fn remove_validator_from_pool(
AccountMeta::new(*pool_mint, false), AccountMeta::new(*pool_mint, false),
AccountMeta::new_readonly(sysvar::clock::id(), false), AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(*token_program_id, false), AccountMeta::new_readonly(*token_program_id, false),
AccountMeta::new_readonly(*stake_program_id, false), AccountMeta::new_readonly(stake::id(), false),
]; ];
Ok(Instruction { Ok(Instruction {
program_id: *program_id, program_id: *program_id,
@ -330,7 +328,6 @@ pub fn deposit(
pool_fee_to: &Pubkey, pool_fee_to: &Pubkey,
pool_mint: &Pubkey, pool_mint: &Pubkey,
token_program_id: &Pubkey, token_program_id: &Pubkey,
stake_program_id: &Pubkey,
) -> Result<Instruction, ProgramError> { ) -> Result<Instruction, ProgramError> {
let accounts = vec![ let accounts = vec![
AccountMeta::new(*stake_pool, false), AccountMeta::new(*stake_pool, false),
@ -345,7 +342,7 @@ pub fn deposit(
AccountMeta::new_readonly(sysvar::clock::id(), false), AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(sysvar::stake_history::id(), false), AccountMeta::new_readonly(sysvar::stake_history::id(), false),
AccountMeta::new_readonly(*token_program_id, false), AccountMeta::new_readonly(*token_program_id, false),
AccountMeta::new_readonly(*stake_program_id, false), AccountMeta::new_readonly(stake::id(), false),
]; ];
Ok(Instruction { Ok(Instruction {
program_id: *program_id, program_id: *program_id,
@ -366,7 +363,6 @@ pub fn withdraw(
burn_from: &Pubkey, burn_from: &Pubkey,
pool_mint: &Pubkey, pool_mint: &Pubkey,
token_program_id: &Pubkey, token_program_id: &Pubkey,
stake_program_id: &Pubkey,
amount: u64, amount: u64,
) -> Result<Instruction, ProgramError> { ) -> Result<Instruction, ProgramError> {
let accounts = vec![ let accounts = vec![
@ -380,7 +376,7 @@ pub fn withdraw(
AccountMeta::new(*pool_mint, false), AccountMeta::new(*pool_mint, false),
AccountMeta::new_readonly(sysvar::clock::id(), false), AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(*token_program_id, false), AccountMeta::new_readonly(*token_program_id, false),
AccountMeta::new_readonly(*stake_program_id, false), AccountMeta::new_readonly(stake::id(), false),
]; ];
Ok(Instruction { Ok(Instruction {
program_id: *program_id, program_id: *program_id,

View File

@ -403,24 +403,38 @@ impl Processor {
let account_info_iter = &mut accounts.iter(); let account_info_iter = &mut accounts.iter();
// Stake pool account // Stake pool account
let stake_pool_info = next_account_info(account_info_iter)?; let stake_pool_info = next_account_info(account_info_iter)?;
// Owner account
let owner_info = next_account_info(account_info_iter)?;
// Account creation funder account // Account creation funder account
let funder_info = next_account_info(account_info_iter)?; let funder_info = next_account_info(account_info_iter)?;
// Stake account to be created // Stake account to be created
let stake_account_info = next_account_info(account_info_iter)?; let stake_account_info = next_account_info(account_info_iter)?;
// Validator this stake account will vote for // Validator this stake account will vote for
let validator_info = next_account_info(account_info_iter)?; let validator_info = next_account_info(account_info_iter)?;
// Stake authority for the new stake account
let stake_authority_info = next_account_info(account_info_iter)?;
// Withdraw authority for the new stake account
let withdraw_authority_info = next_account_info(account_info_iter)?;
// Rent sysvar account // Rent sysvar account
let rent_info = next_account_info(account_info_iter)?; let rent_info = next_account_info(account_info_iter)?;
let rent = &Rent::from_account_info(rent_info)?; let rent = &Rent::from_account_info(rent_info)?;
// Clock sysvar account
let clock_info = next_account_info(account_info_iter)?;
// Stake history sysvar account
let stake_history_info = next_account_info(account_info_iter)?;
// Stake config sysvar account
let stake_config_info = next_account_info(account_info_iter)?;
// System program id // System program id
let system_program_info = next_account_info(account_info_iter)?; let system_program_info = next_account_info(account_info_iter)?;
// Staking program id // Staking program id
let stake_program_info = next_account_info(account_info_iter)?; let stake_program_info = next_account_info(account_info_iter)?;
// Get stake pool stake (and check if it is initialized)
if stake_pool_info.owner != program_id {
return Err(ProgramError::IncorrectProgramId);
}
let stake_pool = StakePool::try_from_slice(&stake_pool_info.data.borrow())?;
if !stake_pool.is_valid() {
return Err(StakePoolError::InvalidState.into());
}
stake_pool.check_owner(owner_info)?;
// Check program ids // Check program ids
if *system_program_info.key != solana_program::system_program::id() { if *system_program_info.key != solana_program::system_program::id() {
return Err(ProgramError::IncorrectProgramId); return Err(ProgramError::IncorrectProgramId);
@ -466,8 +480,8 @@ impl Processor {
&stake::initialize( &stake::initialize(
&stake_account_info.key, &stake_account_info.key,
&stake::Authorized { &stake::Authorized {
staker: *stake_authority_info.key, staker: *owner_info.key,
withdrawer: *withdraw_authority_info.key, withdrawer: *owner_info.key,
}, },
&stake::Lockup::default(), &stake::Lockup::default(),
), ),
@ -476,6 +490,22 @@ impl Processor {
rent_info.clone(), rent_info.clone(),
stake_program_info.clone(), stake_program_info.clone(),
], ],
)?;
invoke(
&stake::delegate_stake(
&stake_account_info.key,
&owner_info.key,
&validator_info.key,
),
&[
stake_account_info.clone(),
validator_info.clone(),
clock_info.clone(),
stake_history_info.clone(),
stake_config_info.clone(),
owner_info.clone(),
],
) )
} }

View File

@ -13,6 +13,10 @@ use std::str::FromStr;
solana_program::declare_id!("Stake11111111111111111111111111111111111111"); solana_program::declare_id!("Stake11111111111111111111111111111111111111");
const STAKE_CONFIG: &str = "StakeConfig11111111111111111111111111111111"; const STAKE_CONFIG: &str = "StakeConfig11111111111111111111111111111111";
/// Id for stake config account
pub fn config_id() -> Pubkey {
Pubkey::from_str(STAKE_CONFIG).unwrap()
}
/// FIXME copied from solana stake program /// FIXME copied from solana stake program
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
@ -489,8 +493,18 @@ pub fn delegate_stake(
AccountMeta::new_readonly(*vote_pubkey, false), AccountMeta::new_readonly(*vote_pubkey, false),
AccountMeta::new_readonly(sysvar::clock::id(), false), AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(sysvar::stake_history::id(), false), AccountMeta::new_readonly(sysvar::stake_history::id(), false),
AccountMeta::new_readonly(Pubkey::from_str(STAKE_CONFIG).unwrap(), false), AccountMeta::new_readonly(config_id(), false),
AccountMeta::new_readonly(*authorized_pubkey, true), AccountMeta::new_readonly(*authorized_pubkey, true),
]; ];
Instruction::new_with_bincode(id(), &StakeInstruction::DelegateStake, account_metas) Instruction::new_with_bincode(id(), &StakeInstruction::DelegateStake, account_metas)
} }
/// FIXME copied from stake program
pub fn deactivate_stake(stake_pubkey: &Pubkey, authorized_pubkey: &Pubkey) -> Instruction {
let account_metas = vec![
AccountMeta::new(*stake_pubkey, false),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(*authorized_pubkey, true),
];
Instruction::new_with_bincode(id(), &StakeInstruction::Deactivate, account_metas)
}

View File

@ -3,12 +3,16 @@
mod helpers; mod helpers;
use { use {
borsh::BorshDeserialize, borsh::{BorshDeserialize, BorshSerialize},
helpers::*, helpers::*,
solana_program::hash::Hash, solana_program::{
hash::Hash,
instruction::{AccountMeta, Instruction, InstructionError},
pubkey::Pubkey,
sysvar,
},
solana_program_test::*, solana_program_test::*,
solana_sdk::{ solana_sdk::{
instruction::InstructionError,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
transaction::Transaction, transaction::Transaction,
transaction::TransactionError, transaction::TransactionError,
@ -237,26 +241,32 @@ async fn test_stake_pool_deposit_with_wrong_stake_program_id() {
.await .await
.unwrap(); .unwrap();
let wrong_stake_program = Keypair::new(); let wrong_stake_program = Pubkey::new_unique();
let mut transaction = Transaction::new_with_payer( let accounts = vec![
&[instruction::deposit( AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false),
&id(), AccountMeta::new(stake_pool_accounts.validator_list.pubkey(), false),
&stake_pool_accounts.stake_pool.pubkey(), AccountMeta::new_readonly(stake_pool_accounts.deposit_authority, false),
&stake_pool_accounts.validator_list.pubkey(), AccountMeta::new_readonly(stake_pool_accounts.withdraw_authority, false),
&stake_pool_accounts.deposit_authority, AccountMeta::new(user_stake.pubkey(), false),
&stake_pool_accounts.withdraw_authority, AccountMeta::new(validator_stake_account.stake_account, false),
&user_stake.pubkey(), AccountMeta::new(user_pool_account.pubkey(), false),
&validator_stake_account.stake_account, AccountMeta::new(stake_pool_accounts.pool_fee_account.pubkey(), false),
&user_pool_account.pubkey(), AccountMeta::new(stake_pool_accounts.pool_mint.pubkey(), false),
&stake_pool_accounts.pool_fee_account.pubkey(), AccountMeta::new_readonly(sysvar::clock::id(), false),
&stake_pool_accounts.pool_mint.pubkey(), AccountMeta::new_readonly(sysvar::stake_history::id(), false),
&spl_token::id(), AccountMeta::new_readonly(spl_token::id(), false),
&wrong_stake_program.pubkey(), AccountMeta::new_readonly(wrong_stake_program, false),
) ];
.unwrap()], let instruction = Instruction {
Some(&payer.pubkey()), program_id: id(),
); accounts,
data: instruction::StakePoolInstruction::Deposit
.try_to_vec()
.unwrap(),
};
let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));
transaction.sign(&[&payer], recent_blockhash); transaction.sign(&[&payer], recent_blockhash);
let transaction_error = banks_client let transaction_error = banks_client
.process_transaction(transaction) .process_transaction(transaction)
@ -392,7 +402,6 @@ async fn test_stake_pool_deposit_with_wrong_token_program_id() {
&stake_pool_accounts.pool_fee_account.pubkey(), &stake_pool_accounts.pool_fee_account.pubkey(),
&stake_pool_accounts.pool_mint.pubkey(), &stake_pool_accounts.pool_mint.pubkey(),
&wrong_token_program.pubkey(), &wrong_token_program.pubkey(),
&stake::id(),
) )
.unwrap()], .unwrap()],
Some(&payer.pubkey()), Some(&payer.pubkey()),
@ -481,88 +490,6 @@ async fn test_stake_pool_deposit_with_wrong_validator_list_account() {
} }
} }
#[tokio::test]
async fn test_stake_pool_deposit_where_stake_acc_not_in_stake_state() {
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
let stake_pool_accounts = StakePoolAccounts::new();
stake_pool_accounts
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash)
.await
.unwrap();
let validator_stake_account = ValidatorStakeAccount::new_with_target_authority(
&stake_pool_accounts.deposit_authority,
&stake_pool_accounts.stake_pool.pubkey(),
);
let user_stake_authority = Keypair::new();
create_validator_stake_account(
&mut banks_client,
&payer,
&recent_blockhash,
&validator_stake_account.stake_pool,
&validator_stake_account.stake_account,
&validator_stake_account.vote.pubkey(),
&user_stake_authority.pubkey(),
&validator_stake_account.target_authority,
)
.await;
let user_pool_account = Keypair::new();
let user = Keypair::new();
create_token_account(
&mut banks_client,
&payer,
&recent_blockhash,
&user_pool_account,
&stake_pool_accounts.pool_mint.pubkey(),
&user.pubkey(),
)
.await
.unwrap();
let user_stake_acc = Keypair::new();
let lockup = stake::Lockup::default();
let authorized = stake::Authorized {
staker: stake_pool_accounts.deposit_authority,
withdrawer: stake_pool_accounts.deposit_authority,
};
create_independent_stake_account(
&mut banks_client,
&payer,
&recent_blockhash,
&user_stake_acc,
&authorized,
&lockup,
)
.await;
let transaction_error = stake_pool_accounts
.deposit_stake(
&mut banks_client,
&payer,
&recent_blockhash,
&user_stake_acc.pubkey(),
&user_pool_account.pubkey(),
&validator_stake_account.stake_account,
)
.await
.err()
.unwrap();
match transaction_error {
TransportError::TransactionError(TransactionError::InstructionError(
_,
InstructionError::Custom(error_index),
)) => {
let program_error = error::StakePoolError::WrongStakeState as u32;
assert_eq!(error_index, program_error);
}
_ => panic!(
"Wrong error occurs while try to make a deposit when stake acc not in stake state"
),
}
}
#[tokio::test] #[tokio::test]
async fn test_stake_pool_deposit_to_unknown_validator() { async fn test_stake_pool_deposit_to_unknown_validator() {
let (mut banks_client, payer, recent_blockhash) = program_test().start().await; let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
@ -577,7 +504,12 @@ async fn test_stake_pool_deposit_to_unknown_validator() {
&stake_pool_accounts.stake_pool.pubkey(), &stake_pool_accounts.stake_pool.pubkey(),
); );
validator_stake_account validator_stake_account
.create_and_delegate(&mut banks_client, &payer, &recent_blockhash) .create_and_delegate(
&mut banks_client,
&payer,
&recent_blockhash,
&stake_pool_accounts.owner,
)
.await; .await;
let user_pool_account = Keypair::new(); let user_pool_account = Keypair::new();

View File

@ -300,30 +300,26 @@ pub async fn create_validator_stake_account(
payer: &Keypair, payer: &Keypair,
recent_blockhash: &Hash, recent_blockhash: &Hash,
stake_pool: &Pubkey, stake_pool: &Pubkey,
owner: &Keypair,
stake_account: &Pubkey, stake_account: &Pubkey,
validator: &Pubkey, validator: &Pubkey,
stake_authority: &Pubkey,
withdraw_authority: &Pubkey,
) { ) {
let mut transaction = Transaction::new_with_payer( let mut transaction = Transaction::new_with_payer(
&[ &[
instruction::create_validator_stake_account( instruction::create_validator_stake_account(
&id(), &id(),
&stake_pool, &stake_pool,
&owner.pubkey(),
&payer.pubkey(), &payer.pubkey(),
&stake_account, &stake_account,
&validator, &validator,
&stake_authority,
&withdraw_authority,
&solana_program::system_program::id(),
&stake::id(),
) )
.unwrap(), .unwrap(),
system_instruction::transfer(&payer.pubkey(), &stake_account, TEST_STAKE_AMOUNT), system_instruction::transfer(&payer.pubkey(), &stake_account, TEST_STAKE_AMOUNT),
], ],
Some(&payer.pubkey()), Some(&payer.pubkey()),
); );
transaction.sign(&[payer], *recent_blockhash); transaction.sign(&[payer, owner], *recent_blockhash);
banks_client.process_transaction(transaction).await.unwrap(); banks_client.process_transaction(transaction).await.unwrap();
} }
@ -393,29 +389,18 @@ impl ValidatorStakeAccount {
mut banks_client: &mut BanksClient, mut banks_client: &mut BanksClient,
payer: &Keypair, payer: &Keypair,
recent_blockhash: &Hash, recent_blockhash: &Hash,
owner: &Keypair,
) { ) {
// make stake account create_vote(&mut banks_client, &payer, &recent_blockhash, &self.vote).await;
let user_stake_authority = Keypair::new();
create_validator_stake_account( create_validator_stake_account(
&mut banks_client, &mut banks_client,
&payer, &payer,
&recent_blockhash, &recent_blockhash,
&self.stake_pool, &self.stake_pool,
owner,
&self.stake_account, &self.stake_account,
&self.vote.pubkey(), &self.vote.pubkey(),
&user_stake_authority.pubkey(),
&self.target_authority,
)
.await;
create_vote(&mut banks_client, &payer, &recent_blockhash, &self.vote).await;
delegate_stake_account(
&mut banks_client,
&payer,
&recent_blockhash,
&self.stake_account,
&user_stake_authority,
&self.vote.pubkey(),
) )
.await; .await;
@ -424,11 +409,22 @@ impl ValidatorStakeAccount {
&payer, &payer,
&recent_blockhash, &recent_blockhash,
&self.stake_account, &self.stake_account,
&user_stake_authority, &owner,
&self.target_authority, &self.target_authority,
stake::StakeAuthorize::Staker, stake::StakeAuthorize::Staker,
) )
.await; .await;
authorize_stake_account(
&mut banks_client,
&payer,
&recent_blockhash,
&self.stake_account,
&owner,
&self.target_authority,
stake::StakeAuthorize::Withdrawer,
)
.await;
} }
} }
@ -542,7 +538,6 @@ impl StakePoolAccounts {
&self.pool_fee_account.pubkey(), &self.pool_fee_account.pubkey(),
&self.pool_mint.pubkey(), &self.pool_mint.pubkey(),
&spl_token::id(), &spl_token::id(),
&stake::id(),
) )
.unwrap()], .unwrap()],
Some(&payer.pubkey()), Some(&payer.pubkey()),
@ -575,7 +570,6 @@ impl StakePoolAccounts {
pool_account, pool_account,
&self.pool_mint.pubkey(), &self.pool_mint.pubkey(),
&spl_token::id(), &spl_token::id(),
&stake::id(),
amount, amount,
) )
.unwrap()], .unwrap()],
@ -606,7 +600,6 @@ impl StakePoolAccounts {
pool_account, pool_account,
&self.pool_mint.pubkey(), &self.pool_mint.pubkey(),
&spl_token::id(), &spl_token::id(),
&stake::id(),
) )
.unwrap()], .unwrap()],
Some(&payer.pubkey()), Some(&payer.pubkey()),
@ -636,7 +629,6 @@ impl StakePoolAccounts {
pool_account, pool_account,
&self.pool_mint.pubkey(), &self.pool_mint.pubkey(),
&spl_token::id(), &spl_token::id(),
&stake::id(),
) )
.unwrap()], .unwrap()],
Some(&payer.pubkey()), Some(&payer.pubkey()),
@ -657,7 +649,12 @@ pub async fn simple_add_validator_to_pool(
&stake_pool_accounts.stake_pool.pubkey(), &stake_pool_accounts.stake_pool.pubkey(),
); );
user_stake user_stake
.create_and_delegate(banks_client, &payer, &recent_blockhash) .create_and_delegate(
banks_client,
&payer,
&recent_blockhash,
&stake_pool_accounts.owner,
)
.await; .await;
let user_pool_account = Keypair::new(); let user_pool_account = Keypair::new();

View File

@ -8,12 +8,12 @@ use {
helpers::*, helpers::*,
solana_program::{ solana_program::{
hash::Hash, hash::Hash,
instruction::{AccountMeta, Instruction}, instruction::{AccountMeta, Instruction, InstructionError},
pubkey::Pubkey,
sysvar, sysvar,
}, },
solana_program_test::*, solana_program_test::*,
solana_sdk::{ solana_sdk::{
instruction::InstructionError,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
transaction::{Transaction, TransactionError}, transaction::{Transaction, TransactionError},
transport::TransportError, transport::TransportError,
@ -43,7 +43,12 @@ async fn setup() -> (
&stake_pool_accounts.stake_pool.pubkey(), &stake_pool_accounts.stake_pool.pubkey(),
); );
user_stake user_stake
.create_and_delegate(&mut banks_client, &payer, &recent_blockhash) .create_and_delegate(
&mut banks_client,
&payer,
&recent_blockhash,
&stake_pool_accounts.owner,
)
.await; .await;
// make pool token account // make pool token account
@ -170,7 +175,6 @@ async fn test_add_validator_to_pool_with_wrong_token_program_id() {
&user_pool_account.pubkey(), &user_pool_account.pubkey(),
&stake_pool_accounts.pool_mint.pubkey(), &stake_pool_accounts.pool_mint.pubkey(),
&stake::id(), &stake::id(),
&stake::id(),
) )
.unwrap()], .unwrap()],
Some(&payer.pubkey()), Some(&payer.pubkey()),
@ -215,7 +219,6 @@ async fn test_add_validator_to_pool_with_wrong_pool_mint_account() {
&user_pool_account.pubkey(), &user_pool_account.pubkey(),
&wrong_pool_mint.pubkey(), &wrong_pool_mint.pubkey(),
&spl_token::id(), &spl_token::id(),
&stake::id(),
) )
.unwrap()], .unwrap()],
Some(&payer.pubkey()), Some(&payer.pubkey()),
@ -264,7 +267,6 @@ async fn test_add_validator_to_pool_with_wrong_validator_list_account() {
&user_pool_account.pubkey(), &user_pool_account.pubkey(),
&stake_pool_accounts.pool_mint.pubkey(), &stake_pool_accounts.pool_mint.pubkey(),
&spl_token::id(), &spl_token::id(),
&stake::id(),
) )
.unwrap()], .unwrap()],
Some(&payer.pubkey()), Some(&payer.pubkey()),
@ -359,7 +361,6 @@ async fn test_not_owner_try_to_add_validator_to_pool() {
&user_pool_account.pubkey(), &user_pool_account.pubkey(),
&stake_pool_accounts.pool_mint.pubkey(), &stake_pool_accounts.pool_mint.pubkey(),
&spl_token::id(), &spl_token::id(),
&stake::id(),
) )
.unwrap()], .unwrap()],
Some(&payer.pubkey()), Some(&payer.pubkey()),
@ -436,69 +437,6 @@ async fn test_not_owner_try_to_add_validator_to_pool_without_signature() {
} }
} }
#[tokio::test]
async fn test_add_validator_to_pool_when_stake_acc_not_in_stake_state() {
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
let stake_pool_accounts = StakePoolAccounts::new();
stake_pool_accounts
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash)
.await
.unwrap();
let user = Keypair::new();
let user_stake = ValidatorStakeAccount::new_with_target_authority(
&stake_pool_accounts.deposit_authority,
&stake_pool_accounts.stake_pool.pubkey(),
);
let user_stake_authority = Keypair::new();
create_validator_stake_account(
&mut banks_client,
&payer,
&recent_blockhash,
&user_stake.stake_pool,
&user_stake.stake_account,
&user_stake.vote.pubkey(),
&user_stake_authority.pubkey(),
&user_stake.target_authority,
)
.await;
let user_pool_account = Keypair::new();
create_token_account(
&mut banks_client,
&payer,
&recent_blockhash,
&user_pool_account,
&stake_pool_accounts.pool_mint.pubkey(),
&user.pubkey(),
)
.await
.unwrap();
let transaction_error = stake_pool_accounts
.add_validator_to_pool(
&mut banks_client,
&payer,
&recent_blockhash,
&user_stake.stake_account,
&user_pool_account.pubkey(),
)
.await
.unwrap();
match transaction_error {
TransportError::TransactionError(TransactionError::InstructionError(
_,
InstructionError::Custom(error_index),
)) => {
let program_error = error::StakePoolError::WrongStakeState as u32;
assert_eq!(error_index, program_error);
}
_ => panic!("Wrong error occurs while try to add validator stake account when it isn't in stake state"),
}
}
#[tokio::test] #[tokio::test]
async fn test_add_validator_to_pool_with_wrong_stake_program_id() { async fn test_add_validator_to_pool_with_wrong_stake_program_id() {
let ( let (
@ -510,25 +448,30 @@ async fn test_add_validator_to_pool_with_wrong_stake_program_id() {
user_pool_account, user_pool_account,
) = setup().await; ) = setup().await;
let wrong_stake_program = Keypair::new(); let wrong_stake_program = Pubkey::new_unique();
let mut transaction = Transaction::new_with_payer( let accounts = vec![
&[instruction::add_validator_to_pool( AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false),
&id(), AccountMeta::new_readonly(stake_pool_accounts.owner.pubkey(), true),
&stake_pool_accounts.stake_pool.pubkey(), AccountMeta::new_readonly(stake_pool_accounts.deposit_authority, false),
&stake_pool_accounts.owner.pubkey(), AccountMeta::new_readonly(stake_pool_accounts.withdraw_authority, false),
&stake_pool_accounts.deposit_authority, AccountMeta::new(stake_pool_accounts.validator_list.pubkey(), false),
&stake_pool_accounts.withdraw_authority, AccountMeta::new(user_stake.stake_account, false),
&stake_pool_accounts.validator_list.pubkey(), AccountMeta::new(user_pool_account.pubkey(), false),
&user_stake.stake_account, AccountMeta::new(stake_pool_accounts.pool_mint.pubkey(), false),
&user_pool_account.pubkey(), AccountMeta::new_readonly(sysvar::clock::id(), false),
&stake_pool_accounts.pool_mint.pubkey(), AccountMeta::new_readonly(sysvar::stake_history::id(), false),
&spl_token::id(), AccountMeta::new_readonly(spl_token::id(), false),
&wrong_stake_program.pubkey(), AccountMeta::new_readonly(wrong_stake_program, false),
) ];
.unwrap()], let instruction = Instruction {
Some(&payer.pubkey()), program_id: id(),
); accounts,
data: instruction::StakePoolInstruction::AddValidatorToPool
.try_to_vec()
.unwrap(),
};
let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));
transaction.sign(&[&payer, &stake_pool_accounts.owner], recent_blockhash); transaction.sign(&[&payer, &stake_pool_accounts.owner], recent_blockhash);
let transaction_error = banks_client let transaction_error = banks_client
.process_transaction(transaction) .process_transaction(transaction)
@ -563,7 +506,12 @@ async fn test_add_too_many_validator_stake_accounts() {
&stake_pool_accounts.stake_pool.pubkey(), &stake_pool_accounts.stake_pool.pubkey(),
); );
user_stake user_stake
.create_and_delegate(&mut banks_client, &payer, &recent_blockhash) .create_and_delegate(
&mut banks_client,
&payer,
&recent_blockhash,
&stake_pool_accounts.owner,
)
.await; .await;
// make pool token account // make pool token account
@ -595,7 +543,12 @@ async fn test_add_too_many_validator_stake_accounts() {
&stake_pool_accounts.stake_pool.pubkey(), &stake_pool_accounts.stake_pool.pubkey(),
); );
user_stake user_stake
.create_and_delegate(&mut banks_client, &payer, &recent_blockhash) .create_and_delegate(
&mut banks_client,
&payer,
&recent_blockhash,
&stake_pool_accounts.owner,
)
.await; .await;
let error = stake_pool_accounts let error = stake_pool_accounts
.add_validator_to_pool( .add_validator_to_pool(

View File

@ -2,22 +2,76 @@
mod helpers; mod helpers;
use crate::solana_program::pubkey::Pubkey; use {
use helpers::*; bincode::deserialize,
borsh::BorshSerialize,
use bincode::deserialize; helpers::*,
use solana_program_test::*; solana_program::{
use solana_sdk::{ instruction::{AccountMeta, Instruction, InstructionError},
instruction::InstructionError, pubkey::Pubkey,
system_program, sysvar,
},
solana_program_test::*,
solana_sdk::{
signature::{Keypair, Signer}, signature::{Keypair, Signer},
transaction::Transaction, transaction::Transaction,
transaction::TransactionError, transaction::TransactionError,
transport::TransportError, transport::TransportError,
},
spl_stake_pool::{error, id, instruction, processor, stake},
}; };
use spl_stake_pool::*;
#[tokio::test] #[tokio::test]
async fn test_create_validator_stake_account() { async fn success_create_validator_stake_account() {
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
let stake_pool_accounts = StakePoolAccounts::new();
stake_pool_accounts
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash)
.await
.unwrap();
let validator = Keypair::new();
create_vote(&mut banks_client, &payer, &recent_blockhash, &validator).await;
let (stake_account, _) = processor::Processor::find_stake_address_for_validator(
&id(),
&validator.pubkey(),
&stake_pool_accounts.stake_pool.pubkey(),
);
let mut transaction = Transaction::new_with_payer(
&[instruction::create_validator_stake_account(
&id(),
&stake_pool_accounts.stake_pool.pubkey(),
&stake_pool_accounts.owner.pubkey(),
&payer.pubkey(),
&stake_account,
&validator.pubkey(),
)
.unwrap()],
Some(&payer.pubkey()),
);
transaction.sign(&[&payer, &stake_pool_accounts.owner], recent_blockhash);
banks_client.process_transaction(transaction).await.unwrap();
// Check authorities
let stake = get_account(&mut banks_client, &stake_account).await;
let stake_state = deserialize::<stake::StakeState>(&stake.data).unwrap();
match stake_state {
stake::StakeState::Stake(meta, stake) => {
assert_eq!(&meta.authorized.staker, &stake_pool_accounts.owner.pubkey());
assert_eq!(
&meta.authorized.withdrawer,
&stake_pool_accounts.owner.pubkey()
);
assert_eq!(stake.delegation.voter_pubkey, validator.pubkey());
}
_ => panic!(),
}
}
#[tokio::test]
async fn fail_create_validator_stake_account_on_non_vote_account() {
let (mut banks_client, payer, recent_blockhash) = program_test().start().await; let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
let stake_pool_accounts = StakePoolAccounts::new(); let stake_pool_accounts = StakePoolAccounts::new();
stake_pool_accounts stake_pool_accounts
@ -26,8 +80,6 @@ async fn test_create_validator_stake_account() {
.unwrap(); .unwrap();
let validator = Pubkey::new_unique(); let validator = Pubkey::new_unique();
let user_stake_authority = Keypair::new();
let user_withdraw_authority = Keypair::new();
let (stake_account, _) = processor::Processor::find_stake_address_for_validator( let (stake_account, _) = processor::Processor::find_stake_address_for_validator(
&id(), &id(),
@ -39,37 +91,136 @@ async fn test_create_validator_stake_account() {
&[instruction::create_validator_stake_account( &[instruction::create_validator_stake_account(
&id(), &id(),
&stake_pool_accounts.stake_pool.pubkey(), &stake_pool_accounts.stake_pool.pubkey(),
&stake_pool_accounts.owner.pubkey(),
&payer.pubkey(), &payer.pubkey(),
&stake_account, &stake_account,
&validator, &validator,
&user_stake_authority.pubkey(),
&user_withdraw_authority.pubkey(),
&solana_program::system_program::id(),
&stake::id(),
) )
.unwrap()], .unwrap()],
Some(&payer.pubkey()), Some(&payer.pubkey()),
); );
transaction.sign(&[&payer], recent_blockhash); transaction.sign(&[&payer, &stake_pool_accounts.owner], recent_blockhash);
banks_client.process_transaction(transaction).await.unwrap(); let transaction_error = banks_client
.process_transaction(transaction)
.await
.err()
.unwrap()
.unwrap();
// Check authorities
let stake = get_account(&mut banks_client, &stake_account).await;
let stake_state = deserialize::<stake::StakeState>(&stake.data).unwrap();
match stake_state {
stake::StakeState::Initialized(meta) => {
assert_eq!(&meta.authorized.staker, &user_stake_authority.pubkey());
assert_eq!( assert_eq!(
&meta.authorized.withdrawer, transaction_error,
&user_withdraw_authority.pubkey() TransactionError::InstructionError(0, InstructionError::IncorrectProgramId,)
); );
} }
_ => panic!(),
}
}
#[tokio::test] #[tokio::test]
async fn test_create_validator_stake_account_with_incorrect_address() { async fn fail_create_validator_stake_account_with_wrong_system_program() {
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
let stake_pool_accounts = StakePoolAccounts::new();
stake_pool_accounts
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash)
.await
.unwrap();
let validator = Pubkey::new_unique();
let (stake_account, _) = processor::Processor::find_stake_address_for_validator(
&id(),
&validator,
&stake_pool_accounts.stake_pool.pubkey(),
);
let wrong_system_program = Pubkey::new_unique();
let accounts = vec![
AccountMeta::new_readonly(stake_pool_accounts.stake_pool.pubkey(), false),
AccountMeta::new_readonly(stake_pool_accounts.owner.pubkey(), true),
AccountMeta::new(payer.pubkey(), true),
AccountMeta::new(stake_account, false),
AccountMeta::new_readonly(validator, false),
AccountMeta::new_readonly(sysvar::rent::id(), false),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
AccountMeta::new_readonly(stake::config_id(), false),
AccountMeta::new_readonly(wrong_system_program, false),
AccountMeta::new_readonly(stake::id(), false),
];
let instruction = Instruction {
program_id: id(),
accounts,
data: instruction::StakePoolInstruction::CreateValidatorStakeAccount
.try_to_vec()
.unwrap(),
};
let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));
transaction.sign(&[&payer, &stake_pool_accounts.owner], recent_blockhash);
let transaction_error = banks_client
.process_transaction(transaction)
.await
.err()
.unwrap()
.unwrap();
assert_eq!(
transaction_error,
TransactionError::InstructionError(0, InstructionError::IncorrectProgramId,)
);
}
#[tokio::test]
async fn fail_create_validator_stake_account_with_wrong_stake_program() {
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
let stake_pool_accounts = StakePoolAccounts::new();
stake_pool_accounts
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash)
.await
.unwrap();
let validator = Pubkey::new_unique();
let (stake_account, _) = processor::Processor::find_stake_address_for_validator(
&id(),
&validator,
&stake_pool_accounts.stake_pool.pubkey(),
);
let wrong_stake_program = Pubkey::new_unique();
let accounts = vec![
AccountMeta::new_readonly(stake_pool_accounts.stake_pool.pubkey(), false),
AccountMeta::new_readonly(stake_pool_accounts.owner.pubkey(), true),
AccountMeta::new(payer.pubkey(), true),
AccountMeta::new(stake_account, false),
AccountMeta::new_readonly(validator, false),
AccountMeta::new_readonly(sysvar::rent::id(), false),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
AccountMeta::new_readonly(stake::config_id(), false),
AccountMeta::new_readonly(system_program::id(), false),
AccountMeta::new_readonly(wrong_stake_program, false),
];
let instruction = Instruction {
program_id: id(),
accounts,
data: instruction::StakePoolInstruction::CreateValidatorStakeAccount
.try_to_vec()
.unwrap(),
};
let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));
transaction.sign(&[&payer, &stake_pool_accounts.owner], recent_blockhash);
let transaction_error = banks_client
.process_transaction(transaction)
.await
.err()
.unwrap()
.unwrap();
assert_eq!(
transaction_error,
TransactionError::InstructionError(0, InstructionError::IncorrectProgramId,)
);
}
#[tokio::test]
async fn fail_create_validator_stake_account_with_incorrect_address() {
let (mut banks_client, payer, recent_blockhash) = program_test().start().await; let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
let stake_pool_accounts = StakePoolAccounts::new(); let stake_pool_accounts = StakePoolAccounts::new();
stake_pool_accounts stake_pool_accounts
@ -78,26 +229,21 @@ async fn test_create_validator_stake_account_with_incorrect_address() {
.unwrap(); .unwrap();
let validator = Pubkey::new_unique(); let validator = Pubkey::new_unique();
let user_stake_authority = Keypair::new();
let user_withdraw_authority = Keypair::new();
let stake_account = Keypair::new(); let stake_account = Keypair::new();
let mut transaction = Transaction::new_with_payer( let mut transaction = Transaction::new_with_payer(
&[instruction::create_validator_stake_account( &[instruction::create_validator_stake_account(
&id(), &id(),
&stake_pool_accounts.stake_pool.pubkey(), &stake_pool_accounts.stake_pool.pubkey(),
&stake_pool_accounts.owner.pubkey(),
&payer.pubkey(), &payer.pubkey(),
&stake_account.pubkey(), &stake_account.pubkey(),
&validator, &validator,
&user_stake_authority.pubkey(),
&user_withdraw_authority.pubkey(),
&solana_program::system_program::id(),
&stake::id(),
) )
.unwrap()], .unwrap()],
Some(&payer.pubkey()), Some(&payer.pubkey()),
); );
transaction.sign(&[&payer], recent_blockhash); transaction.sign(&[&payer, &stake_pool_accounts.owner], recent_blockhash);
let transaction_error = banks_client let transaction_error = banks_client
.process_transaction(transaction) .process_transaction(transaction)
.await .await
@ -117,109 +263,3 @@ async fn test_create_validator_stake_account_with_incorrect_address() {
), ),
} }
} }
#[tokio::test]
async fn test_create_validator_stake_account_with_wrong_system_program() {
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
let stake_pool_accounts = StakePoolAccounts::new();
stake_pool_accounts
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash)
.await
.unwrap();
let validator = Pubkey::new_unique();
let user_stake_authority = Keypair::new();
let user_withdraw_authority = Keypair::new();
let (stake_account, _) = processor::Processor::find_stake_address_for_validator(
&id(),
&validator,
&stake_pool_accounts.stake_pool.pubkey(),
);
let wrong_system_program = Keypair::new();
let mut transaction = Transaction::new_with_payer(
&[instruction::create_validator_stake_account(
&id(),
&stake_pool_accounts.stake_pool.pubkey(),
&payer.pubkey(),
&stake_account,
&validator,
&user_stake_authority.pubkey(),
&user_withdraw_authority.pubkey(),
&wrong_system_program.pubkey(),
&stake::id(),
)
.unwrap()],
Some(&payer.pubkey()),
);
transaction.sign(&[&payer], recent_blockhash);
let transaction_error = banks_client
.process_transaction(transaction)
.await
.err()
.unwrap();
match transaction_error {
TransportError::TransactionError(TransactionError::InstructionError(_, error)) => {
assert_eq!(error, InstructionError::IncorrectProgramId);
}
_ => panic!(
"Wrong error occurs while try to create validator stake account with wrong token program ID"
),
}
}
#[tokio::test]
async fn test_create_validator_stake_account_with_wrong_stake_program() {
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
let stake_pool_accounts = StakePoolAccounts::new();
stake_pool_accounts
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash)
.await
.unwrap();
let validator = Pubkey::new_unique();
let user_stake_authority = Keypair::new();
let user_withdraw_authority = Keypair::new();
let (stake_account, _) = processor::Processor::find_stake_address_for_validator(
&id(),
&validator,
&stake_pool_accounts.stake_pool.pubkey(),
);
let wrong_stake_program = Keypair::new();
let mut transaction = Transaction::new_with_payer(
&[instruction::create_validator_stake_account(
&id(),
&stake_pool_accounts.stake_pool.pubkey(),
&payer.pubkey(),
&stake_account,
&validator,
&user_stake_authority.pubkey(),
&user_withdraw_authority.pubkey(),
&solana_program::system_program::id(),
&wrong_stake_program.pubkey(),
)
.unwrap()],
Some(&payer.pubkey()),
);
transaction.sign(&[&payer], recent_blockhash);
let transaction_error = banks_client
.process_transaction(transaction)
.await
.err()
.unwrap();
match transaction_error {
TransportError::TransactionError(TransactionError::InstructionError(_, error)) => {
assert_eq!(error, InstructionError::IncorrectProgramId);
}
_ => panic!(
"Wrong error occurs while try to create validator stake account with wrong stake program ID"
),
}
}

View File

@ -8,13 +8,12 @@ use {
helpers::*, helpers::*,
solana_program::{ solana_program::{
hash::Hash, hash::Hash,
instruction::{AccountMeta, Instruction}, instruction::{AccountMeta, Instruction, InstructionError},
pubkey::Pubkey, pubkey::Pubkey,
sysvar, sysvar,
}, },
solana_program_test::*, solana_program_test::*,
solana_sdk::{ solana_sdk::{
instruction::InstructionError,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
transaction::{Transaction, TransactionError}, transaction::{Transaction, TransactionError},
transport::TransportError, transport::TransportError,
@ -45,7 +44,12 @@ async fn setup() -> (
&stake_pool_accounts.stake_pool.pubkey(), &stake_pool_accounts.stake_pool.pubkey(),
); );
user_stake user_stake
.create_and_delegate(&mut banks_client, &payer, &recent_blockhash) .create_and_delegate(
&mut banks_client,
&payer,
&recent_blockhash,
&stake_pool_accounts.owner,
)
.await; .await;
// make pool token account // make pool token account
@ -165,26 +169,31 @@ async fn test_remove_validator_from_pool_with_wrong_stake_program_id() {
_, _,
) = setup().await; ) = setup().await;
let wrong_stake_program = Keypair::new(); let wrong_stake_program = Pubkey::new_unique();
let new_authority = Pubkey::new_unique(); let new_authority = Pubkey::new_unique();
let mut transaction = Transaction::new_with_payer( let accounts = vec![
&[instruction::remove_validator_from_pool( AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false),
&id(), AccountMeta::new_readonly(stake_pool_accounts.owner.pubkey(), true),
&stake_pool_accounts.stake_pool.pubkey(), AccountMeta::new_readonly(stake_pool_accounts.withdraw_authority, false),
&stake_pool_accounts.owner.pubkey(), AccountMeta::new_readonly(new_authority, false),
&stake_pool_accounts.withdraw_authority, AccountMeta::new(stake_pool_accounts.validator_list.pubkey(), false),
&new_authority, AccountMeta::new(user_stake.stake_account, false),
&stake_pool_accounts.validator_list.pubkey(), AccountMeta::new(user_pool_account.pubkey(), false),
&user_stake.stake_account, AccountMeta::new(stake_pool_accounts.pool_mint.pubkey(), false),
&user_pool_account.pubkey(), AccountMeta::new_readonly(sysvar::clock::id(), false),
&stake_pool_accounts.pool_mint.pubkey(), AccountMeta::new_readonly(spl_token::id(), false),
&spl_token::id(), AccountMeta::new_readonly(wrong_stake_program, false),
&wrong_stake_program.pubkey(), ];
) let instruction = Instruction {
.unwrap()], program_id: id(),
Some(&payer.pubkey()), accounts,
); data: instruction::StakePoolInstruction::RemoveValidatorFromPool
.try_to_vec()
.unwrap(),
};
let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));
transaction.sign(&[&payer, &stake_pool_accounts.owner], recent_blockhash); transaction.sign(&[&payer, &stake_pool_accounts.owner], recent_blockhash);
let transaction_error = banks_client let transaction_error = banks_client
.process_transaction(transaction) .process_transaction(transaction)
@ -230,7 +239,6 @@ async fn test_remove_validator_from_pool_with_wrong_token_program_id() {
&user_pool_account.pubkey(), &user_pool_account.pubkey(),
&stake_pool_accounts.pool_mint.pubkey(), &stake_pool_accounts.pool_mint.pubkey(),
&wrong_token_program.pubkey(), &wrong_token_program.pubkey(),
&stake::id(),
) )
.unwrap()], .unwrap()],
Some(&payer.pubkey()), Some(&payer.pubkey()),
@ -277,7 +285,6 @@ async fn test_remove_validator_from_pool_with_wrong_pool_mint_account() {
&user_pool_account.pubkey(), &user_pool_account.pubkey(),
&wrong_pool_mint.pubkey(), &wrong_pool_mint.pubkey(),
&spl_token::id(), &spl_token::id(),
&stake::id(),
) )
.unwrap()], .unwrap()],
Some(&payer.pubkey()), Some(&payer.pubkey()),
@ -328,7 +335,6 @@ async fn test_remove_validator_from_pool_with_wrong_validator_list_account() {
&user_pool_account.pubkey(), &user_pool_account.pubkey(),
&stake_pool_accounts.pool_mint.pubkey(), &stake_pool_accounts.pool_mint.pubkey(),
&spl_token::id(), &spl_token::id(),
&stake::id(),
) )
.unwrap()], .unwrap()],
Some(&payer.pubkey()), Some(&payer.pubkey()),
@ -444,7 +450,6 @@ async fn test_not_owner_try_to_remove_validator_from_pool() {
&user_pool_account.pubkey(), &user_pool_account.pubkey(),
&stake_pool_accounts.pool_mint.pubkey(), &stake_pool_accounts.pool_mint.pubkey(),
&spl_token::id(), &spl_token::id(),
&stake::id(),
) )
.unwrap()], .unwrap()],
Some(&payer.pubkey()), Some(&payer.pubkey()),
@ -523,72 +528,6 @@ async fn test_not_owner_try_to_remove_validator_from_pool_without_signature() {
} }
} }
#[tokio::test]
async fn test_remove_validator_from_pool_when_stake_acc_not_in_stake_state() {
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
let stake_pool_accounts = StakePoolAccounts::new();
stake_pool_accounts
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash)
.await
.unwrap();
let user = Keypair::new();
let user_stake = ValidatorStakeAccount::new_with_target_authority(
&stake_pool_accounts.deposit_authority,
&stake_pool_accounts.stake_pool.pubkey(),
);
let user_stake_authority = Keypair::new();
create_validator_stake_account(
&mut banks_client,
&payer,
&recent_blockhash,
&user_stake.stake_pool,
&user_stake.stake_account,
&user_stake.vote.pubkey(),
&user_stake_authority.pubkey(),
&user_stake.target_authority,
)
.await;
let user_pool_account = Keypair::new();
create_token_account(
&mut banks_client,
&payer,
&recent_blockhash,
&user_pool_account,
&stake_pool_accounts.pool_mint.pubkey(),
&user.pubkey(),
)
.await
.unwrap();
let new_authority = Pubkey::new_unique();
let transaction_error = stake_pool_accounts
.remove_validator_from_pool(
&mut banks_client,
&payer,
&recent_blockhash,
&user_stake.stake_account,
&user_pool_account.pubkey(),
&new_authority,
)
.await
.unwrap();
match transaction_error {
TransportError::TransactionError(TransactionError::InstructionError(
_,
InstructionError::Custom(error_index),
)) => {
let program_error = error::StakePoolError::WrongStakeState as u32;
assert_eq!(error_index, program_error);
}
_ => panic!("Wrong error occurs while try to add validator stake account when it isn't in stake state"),
}
}
#[tokio::test] #[tokio::test]
async fn test_remove_validator_from_pool_from_unupdated_stake_pool() {} // TODO async fn test_remove_validator_from_pool_from_unupdated_stake_pool() {} // TODO

View File

@ -3,13 +3,16 @@
mod helpers; mod helpers;
use { use {
borsh::BorshDeserialize, borsh::{BorshDeserialize, BorshSerialize},
helpers::*, helpers::*,
solana_program::hash::Hash, solana_program::{
solana_program::pubkey::Pubkey, hash::Hash,
instruction::{AccountMeta, Instruction, InstructionError},
pubkey::Pubkey,
sysvar,
},
solana_program_test::*, solana_program_test::*,
solana_sdk::{ solana_sdk::{
instruction::InstructionError,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
transaction::{Transaction, TransactionError}, transaction::{Transaction, TransactionError},
transport::TransportError, transport::TransportError,
@ -204,26 +207,30 @@ async fn test_stake_pool_withdraw_with_wrong_stake_program() {
let user_stake_recipient = Keypair::new(); let user_stake_recipient = Keypair::new();
let new_authority = Pubkey::new_unique(); let new_authority = Pubkey::new_unique();
let wrong_stake_program = Keypair::new(); let wrong_stake_program = Pubkey::new_unique();
let mut transaction = Transaction::new_with_payer( let accounts = vec![
&[instruction::withdraw( AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false),
&id(), AccountMeta::new(stake_pool_accounts.validator_list.pubkey(), false),
&stake_pool_accounts.stake_pool.pubkey(), AccountMeta::new_readonly(stake_pool_accounts.withdraw_authority, false),
&stake_pool_accounts.validator_list.pubkey(), AccountMeta::new(validator_stake_account.stake_account, false),
&stake_pool_accounts.withdraw_authority, AccountMeta::new(user_stake_recipient.pubkey(), false),
&validator_stake_account.stake_account, AccountMeta::new_readonly(new_authority, false),
&user_stake_recipient.pubkey(), AccountMeta::new(deposit_info.user_pool_account, false),
&new_authority, AccountMeta::new(stake_pool_accounts.pool_mint.pubkey(), false),
&deposit_info.user_pool_account, AccountMeta::new_readonly(sysvar::clock::id(), false),
&stake_pool_accounts.pool_mint.pubkey(), AccountMeta::new_readonly(spl_token::id(), false),
&spl_token::id(), AccountMeta::new_readonly(wrong_stake_program, false),
&wrong_stake_program.pubkey(), ];
tokens_to_burn, let instruction = Instruction {
) program_id: id(),
.unwrap()], accounts,
Some(&payer.pubkey()), data: instruction::StakePoolInstruction::Withdraw(tokens_to_burn)
); .try_to_vec()
.unwrap(),
};
let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));
transaction.sign(&[&payer], recent_blockhash); transaction.sign(&[&payer], recent_blockhash);
let transaction_error = banks_client let transaction_error = banks_client
.process_transaction(transaction) .process_transaction(transaction)
@ -314,7 +321,6 @@ async fn test_stake_pool_withdraw_with_wrong_token_program_id() {
&deposit_info.user_pool_account, &deposit_info.user_pool_account,
&stake_pool_accounts.pool_mint.pubkey(), &stake_pool_accounts.pool_mint.pubkey(),
&wrong_token_program.pubkey(), &wrong_token_program.pubkey(),
&stake::id(),
tokens_to_burn, tokens_to_burn,
) )
.unwrap()], .unwrap()],
@ -382,112 +388,6 @@ async fn test_stake_pool_withdraw_with_wrong_validator_list() {
} }
} }
#[tokio::test]
async fn test_stake_pool_withdraw_when_stake_acc_not_in_stake_state() {
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
let stake_pool_accounts = StakePoolAccounts::new();
stake_pool_accounts
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash)
.await
.unwrap();
let validator_stake_account = ValidatorStakeAccount::new_with_target_authority(
&stake_pool_accounts.deposit_authority,
&stake_pool_accounts.stake_pool.pubkey(),
);
let user_stake_authority = Keypair::new();
create_validator_stake_account(
&mut banks_client,
&payer,
&recent_blockhash,
&validator_stake_account.stake_pool,
&validator_stake_account.stake_account,
&validator_stake_account.vote.pubkey(),
&user_stake_authority.pubkey(),
&validator_stake_account.target_authority,
)
.await;
let user = Keypair::new();
// make stake account
let user_stake = Keypair::new();
let lockup = stake::Lockup::default();
let authorized = stake::Authorized {
staker: stake_pool_accounts.deposit_authority,
withdrawer: stake_pool_accounts.deposit_authority,
};
create_independent_stake_account(
&mut banks_client,
&payer,
&recent_blockhash,
&user_stake,
&authorized,
&lockup,
)
.await;
// make pool token account
let user_pool_account = Keypair::new();
create_token_account(
&mut banks_client,
&payer,
&recent_blockhash,
&user_pool_account,
&stake_pool_accounts.pool_mint.pubkey(),
&user.pubkey(),
)
.await
.unwrap();
let user_pool_account = user_pool_account.pubkey();
let pool_tokens = get_token_balance(&mut banks_client, &user_pool_account).await;
let tokens_to_burn = pool_tokens / 4;
// Delegate tokens for burning
delegate_tokens(
&mut banks_client,
&payer,
&recent_blockhash,
&user_pool_account,
&user,
&stake_pool_accounts.withdraw_authority,
tokens_to_burn,
)
.await;
// Create stake account to withdraw to
let user_stake_recipient = Keypair::new();
let new_authority = Pubkey::new_unique();
let transaction_error = stake_pool_accounts
.withdraw_stake(
&mut banks_client,
&payer,
&recent_blockhash,
&user_stake_recipient.pubkey(),
&user_pool_account,
&validator_stake_account.stake_account,
&new_authority,
tokens_to_burn,
)
.await
.err()
.unwrap();
match transaction_error {
TransportError::TransactionError(TransactionError::InstructionError(
_,
InstructionError::Custom(error_index),
)) => {
let program_error = error::StakePoolError::WrongStakeState as u32;
assert_eq!(error_index, program_error);
}
_ => panic!("Wrong error occurs while try to withdraw when stake acc not in stake state"),
}
}
#[tokio::test] #[tokio::test]
async fn test_stake_pool_withdraw_from_unknown_validator() { async fn test_stake_pool_withdraw_from_unknown_validator() {
let (mut banks_client, payer, recent_blockhash) = program_test().start().await; let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
@ -502,7 +402,12 @@ async fn test_stake_pool_withdraw_from_unknown_validator() {
&stake_pool_accounts.stake_pool.pubkey(), &stake_pool_accounts.stake_pool.pubkey(),
); );
validator_stake_account validator_stake_account
.create_and_delegate(&mut banks_client, &payer, &recent_blockhash) .create_and_delegate(
&mut banks_client,
&payer,
&recent_blockhash,
&stake_pool_accounts.owner,
)
.await; .await;
let user_stake = ValidatorStakeAccount::new_with_target_authority( let user_stake = ValidatorStakeAccount::new_with_target_authority(
@ -510,7 +415,12 @@ async fn test_stake_pool_withdraw_from_unknown_validator() {
&stake_pool_accounts.stake_pool.pubkey(), &stake_pool_accounts.stake_pool.pubkey(),
); );
user_stake user_stake
.create_and_delegate(&mut banks_client, &payer, &recent_blockhash) .create_and_delegate(
&mut banks_client,
&payer,
&recent_blockhash,
&stake_pool_accounts.owner,
)
.await; .await;
let user_pool_account = Keypair::new(); let user_pool_account = Keypair::new();