fix: stake-pool require signature in SetManager (#2273)

* add check for new_manager's signature in SetManager

* cli arg edit
This commit is contained in:
Han Yang 2021-08-13 21:16:43 -07:00 committed by GitHub
parent 974541c158
commit 11a5551446
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 75 additions and 18 deletions

View File

@ -1311,15 +1311,15 @@ fn command_withdraw(
fn command_set_manager( fn command_set_manager(
config: &Config, config: &Config,
stake_pool_address: &Pubkey, stake_pool_address: &Pubkey,
new_manager: &Option<Pubkey>, new_manager: &Option<Keypair>,
new_fee_receiver: &Option<Pubkey>, new_fee_receiver: &Option<Pubkey>,
) -> CommandResult { ) -> CommandResult {
let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?; let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?;
// If new accounts are missing in the arguments use the old ones // If new accounts are missing in the arguments use the old ones
let new_manager = match new_manager { let (new_manager_pubkey, mut signers): (Pubkey, Vec<&dyn Signer>) = match new_manager {
None => stake_pool.manager, None => (stake_pool.manager, vec![]),
Some(value) => *value, Some(value) => (value.pubkey(), vec![value]),
}; };
let new_fee_receiver = match new_fee_receiver { let new_fee_receiver = match new_fee_receiver {
None => stake_pool.manager_fee_account, None => stake_pool.manager_fee_account,
@ -1336,7 +1336,10 @@ fn command_set_manager(
} }
}; };
let mut signers = vec![config.fee_payer.as_ref(), config.manager.as_ref()]; signers.append(&mut vec![
config.fee_payer.as_ref(),
config.manager.as_ref(),
]);
unique_signers!(signers); unique_signers!(signers);
let transaction = checked_transaction_with_signers( let transaction = checked_transaction_with_signers(
config, config,
@ -1344,7 +1347,7 @@ fn command_set_manager(
&spl_stake_pool::id(), &spl_stake_pool::id(),
stake_pool_address, stake_pool_address,
&config.manager.pubkey(), &config.manager.pubkey(),
&new_manager, &new_manager_pubkey,
&new_fee_receiver, &new_fee_receiver,
)], )],
&signers, &signers,
@ -1999,10 +2002,10 @@ fn main() {
.arg( .arg(
Arg::with_name("new_manager") Arg::with_name("new_manager")
.long("new-manager") .long("new-manager")
.validator(is_pubkey) .validator(is_keypair)
.value_name("ADDRESS") .value_name("KEYPAIR")
.takes_value(true) .takes_value(true)
.help("Public key for the new stake pool manager."), .help("Keypair for the new stake pool manager."),
) )
.arg( .arg(
Arg::with_name("new_fee_receiver") Arg::with_name("new_fee_receiver")
@ -2360,7 +2363,7 @@ fn main() {
} }
("set-manager", Some(arg_matches)) => { ("set-manager", Some(arg_matches)) => {
let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap(); let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap();
let new_manager: Option<Pubkey> = pubkey_of(arg_matches, "new_manager"); let new_manager: Option<Keypair> = keypair_of(arg_matches, "new_manager");
let new_fee_receiver: Option<Pubkey> = pubkey_of(arg_matches, "new_fee_receiver"); let new_fee_receiver: Option<Pubkey> = pubkey_of(arg_matches, "new_fee_receiver");
command_set_manager( command_set_manager(
&config, &config,

View File

@ -1103,7 +1103,7 @@ pub fn set_manager(
let accounts = vec![ let accounts = vec![
AccountMeta::new(*stake_pool, false), AccountMeta::new(*stake_pool, false),
AccountMeta::new_readonly(*manager, true), AccountMeta::new_readonly(*manager, true),
AccountMeta::new_readonly(*new_manager, false), AccountMeta::new_readonly(*new_manager, true),
AccountMeta::new_readonly(*new_fee_receiver, false), AccountMeta::new_readonly(*new_fee_receiver, false),
]; ];
Instruction { Instruction {

View File

@ -2366,6 +2366,10 @@ impl Processor {
} }
stake_pool.check_manager(manager_info)?; stake_pool.check_manager(manager_info)?;
if !new_manager_info.is_signer {
msg!("New manager signature missing");
return Err(StakePoolError::SignatureMissing.into());
}
if stake_pool.pool_mint if stake_pool.pool_mint
!= spl_token::state::Account::unpack_from_slice(&new_manager_fee_info.data.borrow())? != spl_token::state::Account::unpack_from_slice(&new_manager_fee_info.data.borrow())?
@ -2412,7 +2416,7 @@ impl Processor {
Ok(()) Ok(())
} }
/// Processes [SetManager](enum.Instruction.html). /// Processes [SetStaker](enum.Instruction.html).
fn process_set_staker(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { fn process_set_staker(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
let account_info_iter = &mut accounts.iter(); let account_info_iter = &mut accounts.iter();
let stake_pool_info = next_account_info(account_info_iter)?; let stake_pool_info = next_account_info(account_info_iter)?;

View File

@ -71,7 +71,10 @@ async fn test_set_manager() {
)], )],
Some(&payer.pubkey()), Some(&payer.pubkey()),
); );
transaction.sign(&[&payer, &stake_pool_accounts.manager], recent_blockhash); transaction.sign(
&[&payer, &stake_pool_accounts.manager, &new_manager],
recent_blockhash,
);
banks_client.process_transaction(transaction).await.unwrap(); banks_client.process_transaction(transaction).await.unwrap();
let stake_pool = get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await; let stake_pool = get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await;
@ -116,7 +119,7 @@ async fn test_set_manager_by_malicious() {
} }
#[tokio::test] #[tokio::test]
async fn test_set_manager_without_signature() { async fn test_set_manager_without_existing_signature() {
let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, new_pool_fee, new_manager) = let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, new_pool_fee, new_manager) =
setup().await; setup().await;
@ -126,7 +129,7 @@ async fn test_set_manager_without_signature() {
let accounts = vec![ let accounts = vec![
AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false), AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false),
AccountMeta::new_readonly(stake_pool_accounts.manager.pubkey(), false), AccountMeta::new_readonly(stake_pool_accounts.manager.pubkey(), false),
AccountMeta::new_readonly(new_manager.pubkey(), false), AccountMeta::new_readonly(new_manager.pubkey(), true),
AccountMeta::new_readonly(new_pool_fee.pubkey(), false), AccountMeta::new_readonly(new_pool_fee.pubkey(), false),
]; ];
let instruction = Instruction { let instruction = Instruction {
@ -136,7 +139,7 @@ async fn test_set_manager_without_signature() {
}; };
let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey())); let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));
transaction.sign(&[&payer], recent_blockhash); transaction.sign(&[&payer, &new_manager], recent_blockhash);
let transaction_error = banks_client let transaction_error = banks_client
.process_transaction(transaction) .process_transaction(transaction)
.await .await
@ -151,7 +154,51 @@ async fn test_set_manager_without_signature() {
let program_error = error::StakePoolError::SignatureMissing as u32; let program_error = error::StakePoolError::SignatureMissing as u32;
assert_eq!(error_index, program_error); assert_eq!(error_index, program_error);
} }
_ => panic!("Wrong error occurs while try to set new manager without signature"), _ => panic!(
"Wrong error occurs while try to set new manager without existing manager signature"
),
}
}
#[tokio::test]
async fn test_set_manager_without_new_signature() {
let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, new_pool_fee, new_manager) =
setup().await;
let data = instruction::StakePoolInstruction::SetManager
.try_to_vec()
.unwrap();
let accounts = vec![
AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false),
AccountMeta::new_readonly(stake_pool_accounts.manager.pubkey(), true),
AccountMeta::new_readonly(new_manager.pubkey(), false),
AccountMeta::new_readonly(new_pool_fee.pubkey(), false),
];
let instruction = Instruction {
program_id: id(),
accounts,
data,
};
let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));
transaction.sign(&[&payer, &stake_pool_accounts.manager], recent_blockhash);
let transaction_error = banks_client
.process_transaction(transaction)
.await
.err()
.unwrap();
match transaction_error {
TransportError::TransactionError(TransactionError::InstructionError(
_,
InstructionError::Custom(error_index),
)) => {
let program_error = error::StakePoolError::SignatureMissing as u32;
assert_eq!(error_index, program_error);
}
_ => {
panic!("Wrong error occurs while try to set new manager without new manager signature")
}
} }
} }
@ -199,7 +246,10 @@ async fn test_set_manager_with_wrong_mint_for_pool_fee_acc() {
)], )],
Some(&payer.pubkey()), Some(&payer.pubkey()),
); );
transaction.sign(&[&payer, &stake_pool_accounts.manager], recent_blockhash); transaction.sign(
&[&payer, &stake_pool_accounts.manager, &new_manager],
recent_blockhash,
);
let transaction_error = banks_client let transaction_error = banks_client
.process_transaction(transaction) .process_transaction(transaction)
.await .await