Skip to content

Commit d6d41ee

Browse files
lang: Add executable account constraint (#140)
1 parent 7f2ef23 commit d6d41ee

File tree

6 files changed

+57
-4
lines changed

6 files changed

+57
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ incremented for features.
1818
* lang, client, ts: Add event emission and subscriptions ([#89](https://github.com/project-serum/anchor/pull/89)).
1919
* lang/account: Allow namespacing account discriminators ([#128](https://github.com/project-serum/anchor/pull/128)).
2020
* cli: TypeScript migrations ([#132](https://github.com/project-serum/anchor/pull/132)).
21+
* lang: Add `#[account(executable)]` attribute ([#140](https://github.com/project-serum/anchor/pull/140)).
2122

2223
## Breaking Changes
2324

examples/misc/programs/misc/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ pub mod misc {
2727
ctx.accounts.data.idata = idata;
2828
Ok(())
2929
}
30+
31+
pub fn test_executable(ctx: Context<TestExecutable>) -> ProgramResult {
32+
Ok(())
33+
}
3034
}
3135

3236
#[derive(Accounts)]
@@ -39,6 +43,12 @@ pub struct Initialize<'info> {
3943
rent: Sysvar<'info, Rent>,
4044
}
4145

46+
#[derive(Accounts)]
47+
pub struct TestExecutable<'info> {
48+
#[account(executable)]
49+
program: AccountInfo<'info>,
50+
}
51+
4252
#[account]
4353
pub struct Data {
4454
udata: u128,

examples/misc/tests/misc.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,25 @@ describe("misc", () => {
4242
let accInfo = await anchor.getProvider().connection.getAccountInfo(pid);
4343
assert.ok(accInfo.executable);
4444
});
45+
46+
it("Can use the executable attribtue", async () => {
47+
await program.rpc.testExecutable({
48+
accounts: {
49+
program: program.programId,
50+
},
51+
});
52+
53+
await assert.rejects(
54+
async () => {
55+
await program.rpc.testExecutable({
56+
accounts: {
57+
program: program.provider.wallet.publicKey,
58+
},
59+
});
60+
},
61+
(err) => {
62+
return true;
63+
}
64+
);
65+
});
4566
});

lang/syn/src/codegen/accounts.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{
22
AccountField, AccountsStruct, CompositeField, Constraint, ConstraintBelongsTo,
3-
ConstraintLiteral, ConstraintOwner, ConstraintRentExempt, ConstraintSeeds, ConstraintSigner,
4-
Field, Ty,
3+
ConstraintExecutable, ConstraintLiteral, ConstraintOwner, ConstraintRentExempt,
4+
ConstraintSeeds, ConstraintSigner, Field, Ty,
55
};
66
use heck::SnakeCase;
77
use quote::quote;
@@ -305,6 +305,7 @@ pub fn generate_field_constraint(f: &Field, c: &Constraint) -> proc_macro2::Toke
305305
Constraint::Owner(c) => generate_constraint_owner(f, c),
306306
Constraint::RentExempt(c) => generate_constraint_rent_exempt(f, c),
307307
Constraint::Seeds(c) => generate_constraint_seeds(f, c),
308+
Constraint::Executable(c) => generate_constraint_executable(f, c),
308309
}
309310
}
310311

@@ -411,3 +412,15 @@ pub fn generate_constraint_seeds(f: &Field, c: &ConstraintSeeds) -> proc_macro2:
411412
}
412413
}
413414
}
415+
416+
pub fn generate_constraint_executable(
417+
f: &Field,
418+
_c: &ConstraintExecutable,
419+
) -> proc_macro2::TokenStream {
420+
let name = &f.ident;
421+
quote! {
422+
if !#name.to_account_info().executable {
423+
return Err(anchor_lang::solana_program::program_error::ProgramError::Custom(5)) // todo
424+
}
425+
}
426+
}

lang/syn/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ pub enum Constraint {
271271
Owner(ConstraintOwner),
272272
RentExempt(ConstraintRentExempt),
273273
Seeds(ConstraintSeeds),
274+
Executable(ConstraintExecutable),
274275
}
275276

276277
#[derive(Debug)]
@@ -303,6 +304,9 @@ pub struct ConstraintSeeds {
303304
pub seeds: proc_macro2::Group,
304305
}
305306

307+
#[derive(Debug)]
308+
pub struct ConstraintExecutable {}
309+
306310
#[derive(Debug)]
307311
pub struct Error {
308312
pub name: String,

lang/syn/src/parser/accounts.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use crate::{
22
AccountField, AccountsStruct, CompositeField, Constraint, ConstraintBelongsTo,
3-
ConstraintLiteral, ConstraintOwner, ConstraintRentExempt, ConstraintSeeds, ConstraintSigner,
4-
CpiAccountTy, Field, ProgramAccountTy, ProgramStateTy, SysvarTy, Ty,
3+
ConstraintExecutable, ConstraintLiteral, ConstraintOwner, ConstraintRentExempt,
4+
ConstraintSeeds, ConstraintSigner, CpiAccountTy, Field, ProgramAccountTy, ProgramStateTy,
5+
SysvarTy, Ty,
56
};
67

78
pub fn parse(strct: &syn::ItemStruct) -> AccountsStruct {
@@ -270,6 +271,9 @@ fn parse_constraints(anchor: &syn::Attribute) -> (Vec<Constraint>, bool, bool, b
270271
}
271272
};
272273
}
274+
"executable" => {
275+
constraints.push(Constraint::Executable(ConstraintExecutable {}));
276+
}
273277
_ => {
274278
panic!("invalid syntax");
275279
}

0 commit comments

Comments
 (0)