lang: Add zero attribute (#513)

This commit is contained in:
Armani Ferrante 2021-08-25 10:27:27 -07:00 committed by GitHub
parent 142728d271
commit 2604a442fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 87 additions and 31 deletions

View File

@ -83,7 +83,7 @@ pub mod cashiers_check {
#[derive(Accounts)]
pub struct CreateCheck<'info> {
// Check being created.
#[account(init)]
#[account(zero)]
check: ProgramAccount<'info, Check>,
// Check's token vault.
#[account(mut, "&vault.owner == check_signer.key")]

View File

@ -53,7 +53,7 @@ pub struct CreateUser<'info> {
#[derive(Accounts)]
pub struct CreateChatRoom<'info> {
#[account(init)]
#[account(zero)]
chat_room: Loader<'info, ChatRoom>,
}

View File

@ -27,9 +27,9 @@ mod composite {
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(init)]
#[account(zero)]
pub dummy_a: ProgramAccount<'info, DummyA>,
#[account(init)]
#[account(zero)]
pub dummy_b: ProgramAccount<'info, DummyB>,
}

View File

@ -43,7 +43,7 @@ pub struct MutError<'info> {
#[derive(Accounts)]
pub struct HasOneError<'info> {
#[account(init, has_one = owner)]
#[account(zero, has_one = owner)]
my_account: ProgramAccount<'info, HasOneAccount>,
owner: AccountInfo<'info>,
}

View File

@ -106,7 +106,7 @@ pub struct InitializeEscrow<'info> {
)]
pub initializer_deposit_token_account: CpiAccount<'info, TokenAccount>,
pub initializer_receive_token_account: CpiAccount<'info, TokenAccount>,
#[account(init)]
#[account(zero)]
pub escrow_account: ProgramAccount<'info, EscrowAccount>,
pub token_program: AccountInfo<'info>,
}

View File

@ -191,7 +191,7 @@ pub mod ido_pool {
#[derive(Accounts)]
pub struct InitializePool<'info> {
#[account(init)]
#[account(zero)]
pub pool_account: ProgramAccount<'info, PoolAccount>,
pub pool_signer: AccountInfo<'info>,
#[account(

View File

@ -207,7 +207,7 @@ pub struct Auth<'info> {
#[derive(Accounts)]
pub struct CreateVesting<'info> {
// Vesting.
#[account(init)]
#[account(zero)]
vesting: ProgramAccount<'info, Vesting>,
#[account(mut)]
vault: CpiAccount<'info, TokenAccount>,

View File

@ -556,9 +556,9 @@ mod registry {
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(init)]
#[account(zero)]
registrar: ProgramAccount<'info, Registrar>,
#[account(init)]
#[account(zero)]
reward_event_q: ProgramAccount<'info, RewardQueue>,
#[account("pool_mint.decimals == 0")]
pool_mint: CpiAccount<'info, Mint>,
@ -595,7 +595,7 @@ pub struct CreateMember<'info> {
// Stake instance.
registrar: ProgramAccount<'info, Registrar>,
// Member.
#[account(init)]
#[account(zero)]
member: ProgramAccount<'info, Member>,
#[account(signer)]
beneficiary: AccountInfo<'info>,
@ -790,7 +790,7 @@ pub struct StartUnstake<'info> {
pool_mint: AccountInfo<'info>,
// Member.
#[account(init)]
#[account(zero)]
pending_withdrawal: ProgramAccount<'info, PendingWithdrawal>,
#[account(has_one = beneficiary, has_one = registrar)]
member: ProgramAccount<'info, Member>,
@ -924,7 +924,7 @@ pub struct DropReward<'info> {
reward_event_q: ProgramAccount<'info, RewardQueue>,
pool_mint: CpiAccount<'info, Mint>,
// Vendor.
#[account(init)]
#[account(zero)]
vendor: ProgramAccount<'info, RewardVendor>,
#[account(mut)]
vendor_vault: CpiAccount<'info, TokenAccount>,

View File

@ -75,7 +75,7 @@ pub struct RemainingAccounts {}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(init)]
#[account(zero)]
pub data: ProgramAccount<'info, Data>,
}
@ -111,13 +111,13 @@ pub struct TestClose<'info> {
#[derive(Accounts)]
pub struct TestU16<'info> {
#[account(init)]
#[account(zero)]
pub my_account: ProgramAccount<'info, DataU16>,
}
#[derive(Accounts)]
pub struct TestI16<'info> {
#[account(init)]
#[account(zero)]
pub data: ProgramAccount<'info, DataI16>,
}

View File

@ -164,14 +164,14 @@ pub mod multisig {
#[derive(Accounts)]
pub struct CreateMultisig<'info> {
#[account(init)]
#[account(zero)]
multisig: ProgramAccount<'info, Multisig>,
}
#[derive(Accounts)]
pub struct CreateTransaction<'info> {
multisig: ProgramAccount<'info, Multisig>,
#[account(init)]
#[account(zero)]
transaction: ProgramAccount<'info, Transaction>,
// One of the owners. Checked in the handler.
#[account(signer)]

View File

@ -19,7 +19,7 @@ mod basic_1 {
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(init)]
#[account(zero)]
pub my_account: ProgramAccount<'info, MyAccount>,
}

View File

@ -24,7 +24,7 @@ mod basic_2 {
#[derive(Accounts)]
pub struct Create<'info> {
#[account(init)]
#[account(zero)]
pub counter: ProgramAccount<'info, Counter>,
}

View File

@ -16,7 +16,7 @@ pub mod puppet {
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(init)]
#[account(zero)]
pub puppet: ProgramAccount<'info, Puppet>,
}

View File

@ -109,7 +109,7 @@ pub struct SetEvent<'info> {
#[derive(Accounts)]
pub struct CreateFoo<'info> {
#[account(init)]
#[account(zero)]
foo: Loader<'info, Foo>,
#[account(signer)]
authority: AccountInfo<'info>,
@ -165,7 +165,7 @@ pub struct UpdateBar<'info> {
#[derive(Accounts)]
pub struct CreateLargeAccount<'info> {
#[account(init)]
#[account(zero)]
event_q: Loader<'info, EventQ>,
}

View File

@ -1,9 +1,4 @@
use crate::{
CompositeField, Constraint, ConstraintAddress, ConstraintClose, ConstraintExecutable,
ConstraintGroup, ConstraintHasOne, ConstraintInit, ConstraintLiteral, ConstraintMut,
ConstraintOwner, ConstraintRaw, ConstraintRentExempt, ConstraintSeedsGroup, ConstraintSigner,
ConstraintState, Field, PdaKind, Ty,
};
use crate::*;
use proc_macro2_diagnostics::SpanDiagnosticExt;
use quote::quote;
use syn::Expr;
@ -48,6 +43,7 @@ pub fn generate_composite(f: &CompositeField) -> proc_macro2::TokenStream {
pub fn linearize(c_group: &ConstraintGroup) -> Vec<Constraint> {
let ConstraintGroup {
init,
zeroed,
mutable,
signer,
has_one,
@ -70,6 +66,9 @@ pub fn linearize(c_group: &ConstraintGroup) -> Vec<Constraint> {
if let Some(c) = init {
constraints.push(Constraint::Init(c));
}
if let Some(c) = zeroed {
constraints.push(Constraint::Zeroed(c));
}
if let Some(c) = mutable {
constraints.push(Constraint::Mut(c));
}
@ -103,6 +102,7 @@ pub fn linearize(c_group: &ConstraintGroup) -> Vec<Constraint> {
fn generate_constraint(f: &Field, c: &Constraint) -> proc_macro2::TokenStream {
match c {
Constraint::Init(c) => generate_constraint_init(f, c),
Constraint::Zeroed(c) => generate_constraint_zeroed(f, c),
Constraint::Mut(c) => generate_constraint_mut(f, c),
Constraint::HasOne(c) => generate_constraint_has_one(f, c),
Constraint::Signer(c) => generate_constraint_signer(f, c),
@ -140,6 +140,12 @@ pub fn generate_constraint_init(_f: &Field, _c: &ConstraintInit) -> proc_macro2:
quote! {}
}
pub fn generate_constraint_zeroed(_f: &Field, _c: &ConstraintZeroed) -> proc_macro2::TokenStream {
// No constraint. The zero discriminator is checked in `try_accounts_init`
// currently.
quote! {}
}
pub fn generate_constraint_close(f: &Field, c: &ConstraintClose) -> proc_macro2::TokenStream {
let field = &f.ident;
let target = &c.sol_dest;

View File

@ -38,7 +38,7 @@ pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
}
} else {
let name = typed_ident(f);
match f.constraints.is_init() {
match f.constraints.is_init() || f.constraints.is_zeroed() {
false => quote! {
#[cfg(feature = "anchor-debug")]
::solana_program::log::sol_log(stringify!(#name));

View File

@ -263,6 +263,7 @@ pub struct ErrorCode {
#[derive(Debug, Default, Clone)]
pub struct ConstraintGroup {
init: Option<ConstraintInit>,
zeroed: Option<ConstraintZeroed>,
mutable: Option<ConstraintMut>,
signer: Option<ConstraintSigner>,
owner: Option<ConstraintOwner>,
@ -282,6 +283,10 @@ impl ConstraintGroup {
self.init.is_some()
}
pub fn is_zeroed(&self) -> bool {
self.zeroed.is_some()
}
pub fn is_mutable(&self) -> bool {
self.mutable.is_some()
}
@ -302,6 +307,7 @@ impl ConstraintGroup {
#[derive(Debug)]
pub enum Constraint {
Init(ConstraintInit),
Zeroed(ConstraintZeroed),
Mut(ConstraintMut),
Signer(ConstraintSigner),
HasOne(ConstraintHasOne),
@ -321,6 +327,7 @@ pub enum Constraint {
#[derive(Debug)]
pub enum ConstraintToken {
Init(Context<ConstraintInit>),
Zeroed(Context<ConstraintZeroed>),
Mut(Context<ConstraintMut>),
Signer(Context<ConstraintSigner>),
HasOne(Context<ConstraintHasOne>),
@ -351,6 +358,9 @@ impl Parse for ConstraintToken {
#[derive(Debug, Clone)]
pub struct ConstraintInit {}
#[derive(Debug, Clone)]
pub struct ConstraintZeroed {}
#[derive(Debug, Clone)]
pub struct ConstraintMut {}

View File

@ -62,6 +62,7 @@ pub fn parse_token(stream: ParseStream) -> ParseResult<ConstraintToken> {
let c = match kw.as_str() {
"init" => ConstraintToken::Init(Context::new(ident.span(), ConstraintInit {})),
"zero" => ConstraintToken::Zeroed(Context::new(ident.span(), ConstraintZeroed {})),
"mut" => ConstraintToken::Mut(Context::new(ident.span(), ConstraintMut {})),
"signer" => ConstraintToken::Signer(Context::new(ident.span(), ConstraintSigner {})),
"executable" => {
@ -229,6 +230,7 @@ pub fn parse_token(stream: ParseStream) -> ParseResult<ConstraintToken> {
pub struct ConstraintGroupBuilder<'ty> {
pub f_ty: Option<&'ty Ty>,
pub init: Option<Context<ConstraintInit>>,
pub zeroed: Option<Context<ConstraintZeroed>>,
pub mutable: Option<Context<ConstraintMut>>,
pub signer: Option<Context<ConstraintSigner>>,
pub has_one: Vec<Context<ConstraintHasOne>>,
@ -255,6 +257,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
Self {
f_ty,
init: None,
zeroed: None,
mutable: None,
signer: None,
has_one: Vec::new(),
@ -290,6 +293,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
.mutable
.replace(Context::new(i.span(), ConstraintMut {})),
};
// Rent exempt if not explicitly skipped.
if self.rent_exempt.is_none() {
self.rent_exempt
.replace(Context::new(i.span(), ConstraintRentExempt::Enforce));
@ -297,6 +301,25 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
}
// Seeds.
if let Some(z) = &self.zeroed {
match self.mutable {
Some(m) => {
return Err(ParseError::new(
m.span(),
"mut cannot be provided with zeroed",
))
}
None => self
.mutable
.replace(Context::new(z.span(), ConstraintMut {})),
};
// Rent exempt if not explicitly skipped.
if self.rent_exempt.is_none() {
self.rent_exempt
.replace(Context::new(z.span(), ConstraintRentExempt::Enforce));
}
}
if let Some(i) = &self.seeds {
if self.init.is_some() && self.payer.is_none() {
return Err(ParseError::new(
@ -365,6 +388,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
let ConstraintGroupBuilder {
f_ty: _,
init,
zeroed,
mutable,
signer,
has_one,
@ -413,6 +437,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
let is_init = init.is_some();
Ok(ConstraintGroup {
init: into_inner!(init),
zeroed: into_inner!(zeroed),
mutable: into_inner!(mutable),
signer: into_inner!(signer),
has_one: into_inner_vec!(has_one),
@ -469,6 +494,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
pub fn add(&mut self, c: ConstraintToken) -> ParseResult<()> {
match c {
ConstraintToken::Init(c) => self.add_init(c),
ConstraintToken::Zeroed(c) => self.add_zeroed(c),
ConstraintToken::Mut(c) => self.add_mut(c),
ConstraintToken::Signer(c) => self.add_signer(c),
ConstraintToken::HasOne(c) => self.add_has_one(c),
@ -495,10 +521,24 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
if self.init.is_some() {
return Err(ParseError::new(c.span(), "init already provided"));
}
if self.zeroed.is_some() {
return Err(ParseError::new(c.span(), "zeroed already provided"));
}
self.init.replace(c);
Ok(())
}
fn add_zeroed(&mut self, c: Context<ConstraintZeroed>) -> ParseResult<()> {
if self.zeroed.is_some() {
return Err(ParseError::new(c.span(), "zeroed already provided"));
}
if self.init.is_some() {
return Err(ParseError::new(c.span(), "init already provided"));
}
self.zeroed.replace(c);
Ok(())
}
fn add_close(&mut self, c: Context<ConstraintClose>) -> ParseResult<()> {
if !matches!(self.f_ty, Some(Ty::ProgramAccount(_)))
&& !matches!(self.f_ty, Some(Ty::Loader(_)))
@ -700,7 +740,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
if self.seeds.is_none() {
return Err(ParseError::new(
c.span(),
"associated or seeds must be provided before space",
"init must be provided before space",
));
}
if self.space.is_some() {