Skip to content

Commit

Permalink
lang: Require zero accounts to be unique
Browse files Browse the repository at this point in the history
  • Loading branch information
acheroncrypto committed Dec 6, 2024
1 parent a7a23ee commit a5ac560
Showing 1 changed file with 36 additions and 2 deletions.
38 changes: 36 additions & 2 deletions lang/syn/src/codegen/accounts/constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ fn generate_constraint(
) -> proc_macro2::TokenStream {
match c {
Constraint::Init(c) => generate_constraint_init(f, c, accs),
Constraint::Zeroed(c) => generate_constraint_zeroed(f, c),
Constraint::Zeroed(c) => generate_constraint_zeroed(f, c, accs),
Constraint::Mut(c) => generate_constraint_mut(f, c),
Constraint::HasOne(c) => generate_constraint_has_one(f, c, accs),
Constraint::Signer(c) => generate_constraint_signer(f, c),
Expand Down Expand Up @@ -197,14 +197,47 @@ pub fn generate_constraint_init(
generate_constraint_init_group(f, c, accs)
}

pub fn generate_constraint_zeroed(f: &Field, _c: &ConstraintZeroed) -> proc_macro2::TokenStream {
pub fn generate_constraint_zeroed(
f: &Field,
_c: &ConstraintZeroed,
accs: &AccountsStruct,
) -> proc_macro2::TokenStream {
let account_ty = f.account_ty();
let discriminator = quote! { #account_ty::DISCRIMINATOR };

let field = &f.ident;
let name_str = field.to_string();
let ty_decl = f.ty_decl(true);
let from_account_info = f.from_account_info(None, false);

// Require `zero` constraint accounts to be unique by:
//
// 1. Getting the names of all accounts that have the `zero` constraint and are declared before
// the current field (in order to avoid checking the same field).
// 2. Comparing the key of the current field with all the previous fields' keys.
// 3. Returning an error if a match is found.
let unique_account_checks = accs
.fields
.iter()
.filter_map(|af| match af {
AccountField::Field(field) => Some(field),
_ => None,
})
.take_while(|field| field.ident != f.ident)
.filter(|field| field.constraints.is_zeroed())
.map(|field| &field.ident)
.map(|other_field| {
quote! {
if #field.key == &#other_field.key() {
return Err(
anchor_lang::error::Error::from(
anchor_lang::error::ErrorCode::ConstraintZero
).with_account_name(#name_str)
);
}
}
});

quote! {
let #field: #ty_decl = {
let mut __data: &[u8] = &#field.try_borrow_data()?;
Expand All @@ -213,6 +246,7 @@ pub fn generate_constraint_zeroed(f: &Field, _c: &ConstraintZeroed) -> proc_macr
if __has_disc {
return Err(anchor_lang::error::Error::from(anchor_lang::error::ErrorCode::ConstraintZero).with_account_name(#name_str));
}
#(#unique_account_checks)*
#from_account_info
};
}
Expand Down

0 comments on commit a5ac560

Please sign in to comment.