Browse Source

backport #433 to v2

Jack May 5 years ago
parent
commit
d589bba354
1 changed files with 328 additions and 9 deletions
  1. 328 9
      program/src/processor.rs

+ 328 - 9
program/src/processor.rs

@@ -161,19 +161,18 @@ impl Processor {
             return Ok(());
         }
 
-        let mut source_data = source_account_info.data.borrow_mut();
-        let mut dest_data = dest_account_info.data.borrow_mut();
-        Account::unpack_mut(&mut source_data, &mut |source_account: &mut Account| {
-            Account::unpack_mut(&mut dest_data, &mut |dest_account: &mut Account| {
+        let mut source_account = Account::unpack(&source_account_info.data.borrow())?;
+        let mut dest_account = Account::unpack(&dest_account_info.data.borrow())?;
+
                 if source_account.amount < amount {
                     return Err(TokenError::InsufficientFunds.into());
                 }
-                if source_account.mint != dest_account.mint {
-                    return Err(TokenError::MintMismatch.into());
-                }
                 if source_account.is_frozen() || dest_account.is_frozen() {
                     return Err(TokenError::AccountFrozen.into());
                 }
+        if source_account.mint != dest_account.mint {
+            return Err(TokenError::MintMismatch.into());
+        }
 
                 if let Some((mint_info, expected_decimals)) = expected_mint_info {
                     if source_account.mint != *mint_info.key {
@@ -234,9 +233,10 @@ impl Processor {
                         .ok_or(TokenError::Overflow)?;
                 }
 
+        Account::pack(source_account, &mut source_account_info.data.borrow_mut())?;
+        Account::pack(dest_account, &mut dest_account_info.data.borrow_mut())?;
+
                 Ok(())
-            })
-        })
     }
 
     /// Processes an [Approve](enum.TokenInstruction.html) instruction.
@@ -815,6 +815,13 @@ mod tests {
         Processor::process(&instruction.program_id, &account_infos, &instruction.data)
     }
 
+    fn do_process_instruction_dups(
+        instruction: Instruction,
+        account_infos: Vec<AccountInfo>,
+    ) -> ProgramResult {
+        Processor::process(&instruction.program_id, &account_infos, &instruction.data)
+    }
+
     fn return_token_error_as_program_error() -> ProgramError {
         TokenError::MintMismatch.into()
     }
@@ -1089,6 +1096,318 @@ mod tests {
         );
     }
 
+    #[test]
+    fn test_transfer_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 mut 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 mut account2_info: AccountInfo = (&account2_key, false, &mut account2_account).into();
+        let account3_key = pubkey_rand();
+        let mut account3_account = SolanaAccount::new(
+            account_minimum_balance(),
+            Account::get_packed_len(),
+            &program_id,
+        );
+        let account3_info: AccountInfo = (&account3_key, false, &mut account3_account).into();
+        let account4_key = pubkey_rand();
+        let mut account4_account = SolanaAccount::new(
+            account_minimum_balance(),
+            Account::get_packed_len(),
+            &program_id,
+        );
+        let account4_info: AccountInfo = (&account4_key, true, &mut account4_account).into();
+        let multisig_key = pubkey_rand();
+        let mut multisig_account = SolanaAccount::new(
+            multisig_minimum_balance(),
+            Multisig::get_packed_len(),
+            &program_id,
+        );
+        let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into();
+        let owner_key = pubkey_rand();
+        let mut owner_account = SolanaAccount::default();
+        let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into();
+        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();
+
+        // create another account
+        do_process_instruction_dups(
+            initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(),
+            vec![
+                account2_info.clone(),
+                mint_info.clone(),
+                owner_info.clone(),
+                rent_info.clone(),
+            ],
+        )
+        .unwrap();
+
+        // mint to account
+        do_process_instruction_dups(
+            mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(),
+            vec![mint_info.clone(), account1_info.clone(), owner_info.clone()],
+        )
+        .unwrap();
+
+        // source-owner transfer
+        do_process_instruction_dups(
+            transfer(
+                &program_id,
+                &account1_key,
+                &account2_key,
+                &account1_key,
+                &[],
+                500,
+            )
+            .unwrap(),
+            vec![
+                account1_info.clone(),
+                account2_info.clone(),
+                account1_info.clone(),
+            ],
+        )
+        .unwrap();
+
+        // source-owner transfer2
+        do_process_instruction_dups(
+            transfer2(
+                &program_id,
+                &account1_key,
+                &mint_key,
+                &account2_key,
+                &account1_key,
+                &[],
+                500,
+                2,
+            )
+            .unwrap(),
+            vec![
+                account1_info.clone(),
+                mint_info.clone(),
+                account2_info.clone(),
+                account1_info.clone(),
+            ],
+        )
+        .unwrap();
+
+        // source-delegate transfer
+        Account::unpack_unchecked_mut(
+            &mut account1_info.data.borrow_mut(),
+            &mut |account: &mut Account| {
+                account.amount = 1000;
+                account.delegated_amount = 1000;
+                account.delegate = COption::Some(account1_key);
+                account.owner = owner_key;
+                Ok(())
+            },
+        )
+        .unwrap();
+
+        do_process_instruction_dups(
+            transfer(
+                &program_id,
+                &account1_key,
+                &account2_key,
+                &account1_key,
+                &[],
+                500,
+            )
+            .unwrap(),
+            vec![
+                account1_info.clone(),
+                account2_info.clone(),
+                account1_info.clone(),
+            ],
+        )
+        .unwrap();
+
+        // source-delegate transfer2
+        do_process_instruction_dups(
+            transfer2(
+                &program_id,
+                &account1_key,
+                &mint_key,
+                &account2_key,
+                &account1_key,
+                &[],
+                500,
+                2,
+            )
+            .unwrap(),
+            vec![
+                account1_info.clone(),
+                mint_info.clone(),
+                account2_info.clone(),
+                account1_info.clone(),
+            ],
+        )
+        .unwrap();
+
+        // test destination-owner transfer
+        do_process_instruction_dups(
+            initialize_account(&program_id, &account3_key, &mint_key, &account2_key).unwrap(),
+            vec![
+                account3_info.clone(),
+                mint_info.clone(),
+                account2_info.clone(),
+                rent_info.clone(),
+            ],
+        )
+        .unwrap();
+        do_process_instruction_dups(
+            mint_to(&program_id, &mint_key, &account3_key, &owner_key, &[], 1000).unwrap(),
+            vec![mint_info.clone(), account3_info.clone(), owner_info.clone()],
+        )
+        .unwrap();
+
+        account1_info.is_signer = false;
+        account2_info.is_signer = true;
+        do_process_instruction_dups(
+            transfer(
+                &program_id,
+                &account3_key,
+                &account2_key,
+                &account2_key,
+                &[],
+                500,
+            )
+            .unwrap(),
+            vec![
+                account3_info.clone(),
+                account2_info.clone(),
+                account2_info.clone(),
+            ],
+        )
+        .unwrap();
+
+        // destination-owner transfer2
+        do_process_instruction_dups(
+            transfer2(
+                &program_id,
+                &account3_key,
+                &mint_key,
+                &account2_key,
+                &account2_key,
+                &[],
+                500,
+                2,
+            )
+            .unwrap(),
+            vec![
+                account3_info.clone(),
+                mint_info.clone(),
+                account2_info.clone(),
+                account2_info.clone(),
+            ],
+        )
+        .unwrap();
+
+        // test source-multisig signer
+        do_process_instruction_dups(
+            initialize_multisig(&program_id, &multisig_key, &[&account4_key], 1).unwrap(),
+            vec![
+                multisig_info.clone(),
+                rent_info.clone(),
+                account4_info.clone(),
+            ],
+        )
+        .unwrap();
+
+        do_process_instruction_dups(
+            initialize_account(&program_id, &account4_key, &mint_key, &multisig_key).unwrap(),
+            vec![
+                account4_info.clone(),
+                mint_info.clone(),
+                multisig_info.clone(),
+                rent_info.clone(),
+            ],
+        )
+        .unwrap();
+
+        do_process_instruction_dups(
+            mint_to(&program_id, &mint_key, &account4_key, &owner_key, &[], 1000).unwrap(),
+            vec![mint_info.clone(), account4_info.clone(), owner_info.clone()],
+        )
+        .unwrap();
+
+        // source-multisig-signer transfer
+        do_process_instruction_dups(
+            transfer(
+                &program_id,
+                &account4_key,
+                &account2_key,
+                &multisig_key,
+                &[&account4_key],
+                500,
+            )
+            .unwrap(),
+            vec![
+                account4_info.clone(),
+                account2_info.clone(),
+                multisig_info.clone(),
+                account4_info.clone(),
+            ],
+        )
+        .unwrap();
+
+        // source-multisig-signer transfer2
+        do_process_instruction_dups(
+            transfer2(
+                &program_id,
+                &account4_key,
+                &mint_key,
+                &account2_key,
+                &multisig_key,
+                &[&account4_key],
+                500,
+                2,
+            )
+            .unwrap(),
+            vec![
+                account4_info.clone(),
+                mint_info.clone(),
+                account2_info.clone(),
+                multisig_info.clone(),
+                account4_info.clone(),
+            ],
+        )
+        .unwrap();
+    }
+
     #[test]
     fn test_transfer() {
         let program_id = pubkey_rand();