From fac7d1517b338da0a1523210fc1d991f654534fe Mon Sep 17 00:00:00 2001 From: Paul Schaaf Date: Fri, 7 Jan 2022 16:48:32 +0100 Subject: [PATCH 1/5] lang: give better errors for init when programs are missing --- lang/syn/src/lib.rs | 9 +++++ lang/syn/src/parser/accounts/mod.rs | 62 +++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/lang/syn/src/lib.rs b/lang/syn/src/lib.rs index 62ac9fa692..038d22d3e4 100644 --- a/lang/syn/src/lib.rs +++ b/lang/syn/src/lib.rs @@ -154,6 +154,15 @@ pub enum AccountField { CompositeField(CompositeField), } +impl AccountField { + fn ident(&self) -> &Ident { + match self { + AccountField::Field(field) => &field.ident, + AccountField::CompositeField(c_field) => &c_field.ident, + } + } +} + #[derive(Debug)] pub struct Field { pub ident: Ident, diff --git a/lang/syn/src/parser/accounts/mod.rs b/lang/syn/src/parser/accounts/mod.rs index f2c3b5dc0c..48241f9269 100644 --- a/lang/syn/src/parser/accounts/mod.rs +++ b/lang/syn/src/parser/accounts/mod.rs @@ -31,9 +31,71 @@ pub fn parse(strct: &syn::ItemStruct) -> ParseResult { )) } }; + + let _ = constraints_cross_checks(&fields)?; + Ok(AccountsStruct::new(strct.clone(), fields, instruction_api)) } +fn constraints_cross_checks(fields: &[AccountField]) -> ParseResult<()> { + // INIT + let init_field = fields.iter().find(|f| { + if let AccountField::Field(field) = f { + field.constraints.init.is_some() + } else { + false + } + }); + if let Some(init_field) = init_field { + // init needs system program + if fields.iter().all(|f| f.ident() != "system_program") { + return Err(ParseError::new( + init_field.ident().span(), + "the init constraint requires \ + the system_program field to exist in the account \ + validation struct. Use the program type to add \ + the system_program field to your validation struct.", + )); + } + if let AccountField::Field(field) = init_field { + let kind = &field.constraints.init.as_ref().unwrap().kind; + // init token/a_token/mint needs token program + match kind { + InitKind::Program { .. } => (), + InitKind::Token { .. } + | InitKind::AssociatedToken { .. } + | InitKind::Mint { .. } => { + if fields.iter().all(|f| f.ident() != "token_program") { + return Err(ParseError::new( + init_field.ident().span(), + "the init constraint requires \ + the token_program field to exist in the account \ + validation struct. Use the program type to add \ + the token_program field to your validation struct.", + )); + } + } + } + // a_token needs associated token program + if let InitKind::AssociatedToken { .. } = kind { + if fields + .iter() + .all(|f| f.ident() != "associated_token_program") + { + return Err(ParseError::new( + init_field.ident().span(), + "the init constraint requires \ + the associated_token_program field to exist in the account \ + validation struct. Use the program type to add \ + the associated_token_program field to your validation struct.", + )); + } + } + } + } + Ok(()) +} + pub fn parse_account_field(f: &syn::Field, has_instruction_api: bool) -> ParseResult { let ident = f.ident.clone().unwrap(); let account_field = match is_field_primitive(f)? { From d965a589054bcbdbd064e6ccb28984765210c858 Mon Sep 17 00:00:00 2001 From: Paul Schaaf Date: Fri, 7 Jan 2022 16:50:33 +0100 Subject: [PATCH 2/5] docs: changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66c7b4638d..5576afc777 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ incremented for features. ## [Unreleased] +#### Fixes + +*lang: Improved error msgs when required programs are missing when using the `init` constraint([#1257](https://github.com/project-serum/anchor/pull/1257)) + ## [0.20.0] - 2022-01-06 ### Fixes From 9a8bd7acbae9cf56771fb50e850f427142b9ffd5 Mon Sep 17 00:00:00 2001 From: Armani Ferrante Date: Fri, 7 Jan 2022 11:08:51 -0500 Subject: [PATCH 3/5] Update lang/syn/src/parser/accounts/mod.rs --- lang/syn/src/parser/accounts/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/syn/src/parser/accounts/mod.rs b/lang/syn/src/parser/accounts/mod.rs index 48241f9269..2bb0aa1948 100644 --- a/lang/syn/src/parser/accounts/mod.rs +++ b/lang/syn/src/parser/accounts/mod.rs @@ -47,7 +47,7 @@ fn constraints_cross_checks(fields: &[AccountField]) -> ParseResult<()> { } }); if let Some(init_field) = init_field { - // init needs system program + // init needs system program. if fields.iter().all(|f| f.ident() != "system_program") { return Err(ParseError::new( init_field.ident().span(), From 3424288a1564057723bfbd0c183fc2ca32cdfc70 Mon Sep 17 00:00:00 2001 From: Armani Ferrante Date: Fri, 7 Jan 2022 11:08:56 -0500 Subject: [PATCH 4/5] Update lang/syn/src/parser/accounts/mod.rs --- lang/syn/src/parser/accounts/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/syn/src/parser/accounts/mod.rs b/lang/syn/src/parser/accounts/mod.rs index 2bb0aa1948..d2b64e9c27 100644 --- a/lang/syn/src/parser/accounts/mod.rs +++ b/lang/syn/src/parser/accounts/mod.rs @@ -59,7 +59,7 @@ fn constraints_cross_checks(fields: &[AccountField]) -> ParseResult<()> { } if let AccountField::Field(field) = init_field { let kind = &field.constraints.init.as_ref().unwrap().kind; - // init token/a_token/mint needs token program + // init token/a_token/mint needs token program. match kind { InitKind::Program { .. } => (), InitKind::Token { .. } From 9c5d25eaff23cfae78561cc80524bde42bd102cd Mon Sep 17 00:00:00 2001 From: Armani Ferrante Date: Fri, 7 Jan 2022 11:09:01 -0500 Subject: [PATCH 5/5] Update lang/syn/src/parser/accounts/mod.rs --- lang/syn/src/parser/accounts/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/syn/src/parser/accounts/mod.rs b/lang/syn/src/parser/accounts/mod.rs index d2b64e9c27..2f92212d35 100644 --- a/lang/syn/src/parser/accounts/mod.rs +++ b/lang/syn/src/parser/accounts/mod.rs @@ -76,7 +76,7 @@ fn constraints_cross_checks(fields: &[AccountField]) -> ParseResult<()> { } } } - // a_token needs associated token program + // a_token needs associated token program. if let InitKind::AssociatedToken { .. } = kind { if fields .iter()