Browse Source

lang: Add executable account constraint (#140)

Armani Ferrante 4 years ago
parent
commit
d6d41eee59

+ 1 - 0
CHANGELOG.md

@@ -18,6 +18,7 @@ incremented for features.
 * lang, client, ts: Add event emission and subscriptions ([#89](https://github.com/project-serum/anchor/pull/89)).
 * lang/account: Allow namespacing account discriminators ([#128](https://github.com/project-serum/anchor/pull/128)).
 * cli: TypeScript migrations ([#132](https://github.com/project-serum/anchor/pull/132)).
+* lang: Add `#[account(executable)]` attribute ([#140](https://github.com/project-serum/anchor/pull/140)).
 
 ## Breaking Changes
 

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

@@ -27,6 +27,10 @@ pub mod misc {
         ctx.accounts.data.idata = idata;
         Ok(())
     }
+
+    pub fn test_executable(ctx: Context<TestExecutable>) -> ProgramResult {
+        Ok(())
+    }
 }
 
 #[derive(Accounts)]
@@ -39,6 +43,12 @@ pub struct Initialize<'info> {
     rent: Sysvar<'info, Rent>,
 }
 
+#[derive(Accounts)]
+pub struct TestExecutable<'info> {
+    #[account(executable)]
+    program: AccountInfo<'info>,
+}
+
 #[account]
 pub struct Data {
     udata: u128,

+ 21 - 0
examples/misc/tests/misc.js

@@ -42,4 +42,25 @@ describe("misc", () => {
     let accInfo = await anchor.getProvider().connection.getAccountInfo(pid);
     assert.ok(accInfo.executable);
   });
+
+  it("Can use the executable attribtue", async () => {
+    await program.rpc.testExecutable({
+      accounts: {
+        program: program.programId,
+      },
+    });
+
+    await assert.rejects(
+      async () => {
+        await program.rpc.testExecutable({
+          accounts: {
+            program: program.provider.wallet.publicKey,
+          },
+        });
+      },
+      (err) => {
+        return true;
+      }
+    );
+  });
 });

+ 15 - 2
lang/syn/src/codegen/accounts.rs

@@ -1,7 +1,7 @@
 use crate::{
     AccountField, AccountsStruct, CompositeField, Constraint, ConstraintBelongsTo,
-    ConstraintLiteral, ConstraintOwner, ConstraintRentExempt, ConstraintSeeds, ConstraintSigner,
-    Field, Ty,
+    ConstraintExecutable, ConstraintLiteral, ConstraintOwner, ConstraintRentExempt,
+    ConstraintSeeds, ConstraintSigner, Field, Ty,
 };
 use heck::SnakeCase;
 use quote::quote;
@@ -305,6 +305,7 @@ pub fn generate_field_constraint(f: &Field, c: &Constraint) -> proc_macro2::Toke
         Constraint::Owner(c) => generate_constraint_owner(f, c),
         Constraint::RentExempt(c) => generate_constraint_rent_exempt(f, c),
         Constraint::Seeds(c) => generate_constraint_seeds(f, c),
+        Constraint::Executable(c) => generate_constraint_executable(f, c),
     }
 }
 
@@ -411,3 +412,15 @@ pub fn generate_constraint_seeds(f: &Field, c: &ConstraintSeeds) -> proc_macro2:
         }
     }
 }
+
+pub fn generate_constraint_executable(
+    f: &Field,
+    _c: &ConstraintExecutable,
+) -> proc_macro2::TokenStream {
+    let name = &f.ident;
+    quote! {
+        if !#name.to_account_info().executable {
+            return Err(anchor_lang::solana_program::program_error::ProgramError::Custom(5)) // todo
+        }
+    }
+}

+ 4 - 0
lang/syn/src/lib.rs

@@ -271,6 +271,7 @@ pub enum Constraint {
     Owner(ConstraintOwner),
     RentExempt(ConstraintRentExempt),
     Seeds(ConstraintSeeds),
+    Executable(ConstraintExecutable),
 }
 
 #[derive(Debug)]
@@ -303,6 +304,9 @@ pub struct ConstraintSeeds {
     pub seeds: proc_macro2::Group,
 }
 
+#[derive(Debug)]
+pub struct ConstraintExecutable {}
+
 #[derive(Debug)]
 pub struct Error {
     pub name: String,

+ 6 - 2
lang/syn/src/parser/accounts.rs

@@ -1,7 +1,8 @@
 use crate::{
     AccountField, AccountsStruct, CompositeField, Constraint, ConstraintBelongsTo,
-    ConstraintLiteral, ConstraintOwner, ConstraintRentExempt, ConstraintSeeds, ConstraintSigner,
-    CpiAccountTy, Field, ProgramAccountTy, ProgramStateTy, SysvarTy, Ty,
+    ConstraintExecutable, ConstraintLiteral, ConstraintOwner, ConstraintRentExempt,
+    ConstraintSeeds, ConstraintSigner, CpiAccountTy, Field, ProgramAccountTy, ProgramStateTy,
+    SysvarTy, Ty,
 };
 
 pub fn parse(strct: &syn::ItemStruct) -> AccountsStruct {
@@ -270,6 +271,9 @@ fn parse_constraints(anchor: &syn::Attribute) -> (Vec<Constraint>, bool, bool, b
                         }
                     };
                 }
+                "executable" => {
+                    constraints.push(Constraint::Executable(ConstraintExecutable {}));
+                }
                 _ => {
                     panic!("invalid syntax");
                 }