瀏覽代碼

lang: add rent exempt check for init_if_needed when init is not needed (#1250)

Paul 3 年之前
父節點
當前提交
4d4cba5add

+ 1 - 0
CHANGELOG.md

@@ -13,6 +13,7 @@ incremented for features.
 
 ### Fixes
 
+* lang: `init_if_needed` now checks rent exemption when init is not needed ([#1250](https://github.com/project-serum/anchor/pull/1250)).
 * lang: Add missing owner check when `associated_token::authority` is used ([#1240](https://github.com/project-serum/anchor/pull/1240)).
 * ts: Add type declarations for conditional `workspace` and `Wallet` exports ([#1137](https://github.com/project-serum/anchor/pull/1137)).
 * ts: Change commitment message `recent` to `processed` and `max` to `finalized` ([#1128](https://github.com/project-serum/anchor/pull/1128))

+ 7 - 0
lang/syn/src/codegen/accounts/constraints.rs

@@ -621,6 +621,13 @@ pub fn generate_init(
                             return Err(anchor_lang::__private::ErrorCode::ConstraintOwner.into());
                         }
 
+                        {
+                            let required_lamports = __anchor_rent.minimum_balance(space);
+                            if pa.to_account_info().lamports() < required_lamports {
+                                return Err(anchor_lang::__private::ErrorCode::ConstraintRentExempt.into());
+                            }
+                        }
+
                         #pda_check
                     }
                     pa

+ 19 - 0
tests/misc/programs/misc/src/context.rs

@@ -360,3 +360,22 @@ pub struct EnforceRentExempt<'info> {
     #[account(rent_exempt = enforce)]
     pub data: AccountInfo<'info>,
 }
+
+#[derive(Accounts)]
+pub struct InitDecreaseLamports<'info> {
+    #[account(init, payer = user, space = 1000)]
+    pub data: AccountInfo<'info>,
+    #[account(mut)]
+    pub user: Signer<'info>,
+    pub system_program: Program<'info, System>
+}
+
+#[derive(Accounts)]
+pub struct InitIfNeededChecksRentExemption<'info> {
+    #[account(init_if_needed, payer = user, space = 1000)]
+    pub data: AccountInfo<'info>,
+    #[account(mut)]
+    pub user: Signer<'info>,
+    pub system_program: Program<'info, System>
+}
+

+ 10 - 0
tests/misc/programs/misc/src/lib.rs

@@ -258,4 +258,14 @@ pub mod misc {
     pub fn test_enforce_rent_exempt(ctx: Context<EnforceRentExempt>) -> ProgramResult {
         Ok(())
     }
+
+    pub fn init_decrease_lamports(ctx: Context<InitDecreaseLamports>) -> ProgramResult {
+        **ctx.accounts.data.try_borrow_mut_lamports()? -= 1;
+        **ctx.accounts.user.try_borrow_mut_lamports()? += 1;
+        Ok(())
+    }
+    
+    pub fn init_if_needed_checks_rent_exemption(_ctx: Context<InitIfNeededChecksRentExemption>) -> ProgramResult {
+        Ok(())
+    }
 }

+ 26 - 0
tests/misc/tests/misc.js

@@ -1398,6 +1398,32 @@ describe("misc", () => {
     }
   });
 
+  it("init_if_needed checks rent_exemption if init is not needed", async () => {
+    const data = anchor.web3.Keypair.generate();
+    await program.rpc.initDecreaseLamports({
+      accounts: {
+        data: data.publicKey,
+        user: anchor.getProvider().wallet.publicKey,
+        systemProgram: SystemProgram.programId,
+      },
+      signers: [data],
+    });
+
+    try {
+      await program.rpc.initIfNeededChecksRentExemption({
+        accounts: {
+          data: data.publicKey,
+          user: anchor.getProvider().wallet.publicKey,
+          systemProgram: SystemProgram.programId,
+        },
+        signers: [data],
+      });
+      assert.ok(false);
+    } catch (err) {
+      assert.equal(err.code, 2005);
+    }
+  });
+
   it("Can use multidimensional array", async () => {
     const array2d = new Array(10).fill(new Array(10).fill(99));
     const data = anchor.web3.Keypair.generate();