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

View File

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

View File

@ -2366,6 +2366,10 @@ impl Processor {
}
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
!= spl_token::state::Account::unpack_from_slice(&new_manager_fee_info.data.borrow())?
@ -2412,7 +2416,7 @@ impl Processor {
Ok(())
}
/// Processes [SetManager](enum.Instruction.html).
/// Processes [SetStaker](enum.Instruction.html).
fn process_set_staker(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
let account_info_iter = &mut accounts.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()),
);
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();
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]
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) =
setup().await;
@ -126,7 +129,7 @@ async fn test_set_manager_without_signature() {
let accounts = vec![
AccountMeta::new(stake_pool_accounts.stake_pool.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),
];
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()));
transaction.sign(&[&payer], recent_blockhash);
transaction.sign(&[&payer, &new_manager], recent_blockhash);
let transaction_error = banks_client
.process_transaction(transaction)
.await
@ -151,7 +154,51 @@ async fn test_set_manager_without_signature() {
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 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()),
);
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
.process_transaction(transaction)
.await