lang: Add executable account constraint (#140)

This commit is contained in:
Armani Ferrante 2021-04-03 15:13:12 -07:00 committed by GitHub
parent 7f2ef239ac
commit d6d41eee59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 57 additions and 4 deletions

View File

@ -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

View File

@ -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,

View File

@ -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;
}
);
});
});

View File

@ -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
}
}
}

View File

@ -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,

View File

@ -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");
}