Skip to content

Commit

Permalink
Allow source to be owner/close_authority in CloseAccount (solana-labs…
Browse files Browse the repository at this point in the history
…#438)

* Add failing tests

* No need to hold source RefMut in process_close_account and process_toggle_freeze_account
  • Loading branch information
CriesofCarrots authored Sep 12, 2020
1 parent 1fcc84b commit 6c9e8ac
Showing 1 changed file with 210 additions and 50 deletions.
260 changes: 210 additions & 50 deletions token/program-v3/src/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,32 +552,32 @@ impl Processor {
let dest_account_info = next_account_info(account_info_iter)?;
let authority_info = next_account_info(account_info_iter)?;

let mut source_data = source_account_info.data.borrow_mut();
Account::unpack_mut(&mut source_data, &mut |source_account: &mut Account| {
if !source_account.is_native() && source_account.amount != 0 {
return Err(TokenError::NonNativeHasBalance.into());
}
let mut source_account = Account::unpack(&source_account_info.data.borrow())?;
if !source_account.is_native() && source_account.amount != 0 {
return Err(TokenError::NonNativeHasBalance.into());
}

let authority = source_account
.close_authority
.unwrap_or(source_account.owner);
Self::validate_owner(
program_id,
&authority,
authority_info,
account_info_iter.as_slice(),
)?;
let authority = source_account
.close_authority
.unwrap_or(source_account.owner);
Self::validate_owner(
program_id,
&authority,
authority_info,
account_info_iter.as_slice(),
)?;

let dest_starting_lamports = dest_account_info.lamports();
**dest_account_info.lamports.borrow_mut() = dest_starting_lamports
.checked_add(source_account_info.lamports())
.ok_or(TokenError::Overflow)?;

let dest_starting_lamports = dest_account_info.lamports();
**dest_account_info.lamports.borrow_mut() = dest_starting_lamports
.checked_add(source_account_info.lamports())
.ok_or(TokenError::Overflow)?;
**source_account_info.lamports.borrow_mut() = 0;
source_account.amount = 0;

**source_account_info.lamports.borrow_mut() = 0;
source_account.amount = 0;
Account::pack(source_account, &mut source_account_info.data.borrow_mut())?;

Ok(())
})
Ok(())
}

/// Processes a [FreezeAccount](enum.TokenInstruction.html) or a
Expand All @@ -592,37 +592,37 @@ impl Processor {
let mint_info = next_account_info(account_info_iter)?;
let authority_info = next_account_info(account_info_iter)?;

let mut source_data = source_account_info.data.borrow_mut();
Account::unpack_mut(&mut source_data, &mut |source_account: &mut Account| {
if source_account.is_native() {
return Err(TokenError::NativeNotSupported.into());
}
if mint_info.key != &source_account.mint {
return Err(TokenError::MintMismatch.into());
}
if freeze && source_account.is_frozen() || !freeze && !source_account.is_frozen() {
return Err(TokenError::InvalidState.into());
}
let mut source_account = Account::unpack(&source_account_info.data.borrow())?;
if source_account.is_native() {
return Err(TokenError::NativeNotSupported.into());
}
if mint_info.key != &source_account.mint {
return Err(TokenError::MintMismatch.into());
}
if freeze && source_account.is_frozen() || !freeze && !source_account.is_frozen() {
return Err(TokenError::InvalidState.into());
}

let mint = Mint::unpack(&mint_info.data.borrow_mut())?;
match mint.freeze_authority {
COption::Some(authority) => Self::validate_owner(
program_id,
&authority,
authority_info,
account_info_iter.as_slice(),
),
COption::None => Err(TokenError::MintCannotFreeze.into()),
}?;
let mint = Mint::unpack(&mint_info.data.borrow_mut())?;
match mint.freeze_authority {
COption::Some(authority) => Self::validate_owner(
program_id,
&authority,
authority_info,
account_info_iter.as_slice(),
),
COption::None => Err(TokenError::MintCannotFreeze.into()),
}?;

source_account.state = if freeze {
AccountState::Frozen
} else {
AccountState::Initialized
};
source_account.state = if freeze {
AccountState::Frozen
} else {
AccountState::Initialized
};

Ok(())
})
Account::pack(source_account, &mut source_account_info.data.borrow_mut())?;

Ok(())
}

/// Processes an [Instruction](enum.Instruction.html).
Expand Down Expand Up @@ -3566,6 +3566,97 @@ mod tests {
signers[5].is_signer = true;
}

#[test]
fn test_close_account_dups() {
let program_id = pubkey_rand();
let account1_key = pubkey_rand();
let mut account1_account = SolanaAccount::new(
account_minimum_balance(),
Account::get_packed_len(),
&program_id,
);
let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into();
let account2_key = pubkey_rand();
let mut account2_account = SolanaAccount::new(
account_minimum_balance(),
Account::get_packed_len(),
&program_id,
);
let account2_info: AccountInfo = (&account2_key, true, &mut account2_account).into();
let owner_key = pubkey_rand();
let mint_key = pubkey_rand();
let mut mint_account =
SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into();
let rent_key = rent::id();
let mut rent_sysvar = rent_sysvar();
let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into();

// create mint
do_process_instruction_dups(
initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
vec![mint_info.clone(), rent_info.clone()],
)
.unwrap();

// create account
do_process_instruction_dups(
initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(),
vec![
account1_info.clone(),
mint_info.clone(),
account1_info.clone(),
rent_info.clone(),
],
)
.unwrap();

// source-owner close
do_process_instruction_dups(
close_account(
&program_id,
&account1_key,
&account2_key,
&account1_key,
&[],
)
.unwrap(),
vec![
account1_info.clone(),
account2_info.clone(),
account1_info.clone(),
],
)
.unwrap();

// source-close-authority close
Account::unpack_unchecked_mut(
&mut account1_info.data.borrow_mut(),
&mut |account: &mut Account| {
account.close_authority = COption::Some(account1_key);
account.owner = owner_key;
Ok(())
},
)
.unwrap();
do_process_instruction_dups(
close_account(
&program_id,
&account1_key,
&account2_key,
&account1_key,
&[],
)
.unwrap(),
vec![
account1_info.clone(),
account2_info.clone(),
account1_info.clone(),
],
)
.unwrap();
}

#[test]
fn test_close_account() {
let program_id = pubkey_rand();
Expand Down Expand Up @@ -4389,6 +4480,75 @@ mod tests {
);
}

#[test]
fn test_freeze_thaw_dups() {
let program_id = pubkey_rand();
let account1_key = pubkey_rand();
let mut account1_account = SolanaAccount::new(
account_minimum_balance(),
Account::get_packed_len(),
&program_id,
);
let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into();
let owner_key = pubkey_rand();
let mint_key = pubkey_rand();
let mut mint_account =
SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into();
let rent_key = rent::id();
let mut rent_sysvar = rent_sysvar();
let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into();

// create mint
do_process_instruction_dups(
initialize_mint(&program_id, &mint_key, &owner_key, Some(&account1_key), 2).unwrap(),
vec![mint_info.clone(), rent_info.clone()],
)
.unwrap();

// create account
do_process_instruction_dups(
initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(),
vec![
account1_info.clone(),
mint_info.clone(),
account1_info.clone(),
rent_info.clone(),
],
)
.unwrap();

// freeze where mint freeze_authority is account
do_process_instruction_dups(
freeze_account(&program_id, &account1_key, &mint_key, &account1_key, &[]).unwrap(),
vec![
account1_info.clone(),
mint_info.clone(),
account1_info.clone(),
],
)
.unwrap();

// thaw where mint freeze_authority is account
Account::unpack_unchecked_mut(
&mut account1_info.data.borrow_mut(),
&mut |account: &mut Account| {
account.state = AccountState::Frozen;
Ok(())
},
)
.unwrap();
do_process_instruction_dups(
thaw_account(&program_id, &account1_key, &mint_key, &account1_key, &[]).unwrap(),
vec![
account1_info.clone(),
mint_info.clone(),
account1_info.clone(),
],
)
.unwrap();
}

#[test]
fn test_freeze_account() {
let program_id = pubkey_rand();
Expand Down

0 comments on commit 6c9e8ac

Please sign in to comment.