diff --git a/token/program/src/processor.rs b/token/program/src/processor.rs index 38d3cbc19605f1..4618abea1f01ac 100644 --- a/token/program/src/processor.rs +++ b/token/program/src/processor.rs @@ -552,8 +552,7 @@ 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| { + 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()); } @@ -576,8 +575,9 @@ impl Processor { **source_account_info.lamports.borrow_mut() = 0; source_account.amount = 0; + Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; + Ok(()) - }) } /// Processes a [FreezeAccount](enum.TokenInstruction.html) or a @@ -592,8 +592,7 @@ 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| { + let mut source_account = Account::unpack(&source_account_info.data.borrow())?; if source_account.is_native() { return Err(TokenError::NativeNotSupported.into()); } @@ -621,8 +620,9 @@ impl Processor { AccountState::Initialized }; + Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; + Ok(()) - }) } /// Processes an [Instruction](enum.Instruction.html). @@ -3567,6 +3567,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(); @@ -4390,6 +4481,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();