How would you solve this? Making sure you use all the right practices in the right places.
https://github.com/solana-foundation/anchor/issues/3727
<aside> 💡
DO NOT INTERACT WITH THE ISSUE, DO NOT CREATE A PR FOR IT. JUST WRITE THE PATCH FOR IT.
</aside>
Mild solution
diff --git a/lang/syn/src/codegen/accounts/constraints.rs b/lang/syn/src/codegen/accounts/constraints.rs
index dd4bdef9..970311eb 100644
--- a/lang/syn/src/codegen/accounts/constraints.rs
+++ b/lang/syn/src/codegen/accounts/constraints.rs
@@ -500,13 +500,24 @@ fn generate_constraint_init_group(
// If the seeds came with a trailing comma, we need to chop it off
// before we interpolate them below.
- if let Some(pair) = seeds.pop() {
- seeds.push_value(pair.into_value());
+
+ match seeds {
+ SeedExpr::Puntuated(s) => {
+ if let Some(pair) = s.pop() {
+ s.push_value(pair.into_value());
+ }
+ }
+ _ => {}
}
- let maybe_seeds_plus_comma = (!seeds.is_empty()).then(|| {
- quote! { #seeds, }
- });
+ let seeds_defination = match seeds {
+ SeedExpr::Puntuated(s) => {
+ quote! { [#s] }
+ },
+ SeedExpr::Func(s) => {
+ quote! { #s }
+ }
+ };
let validate_pda = {
// If the bump is provided with init *and target*, then force it to be the
@@ -545,18 +556,18 @@ fn generate_constraint_init_group(
(
quote! {
+ let __seeds = #seeds_defination;
+ let __seed_slices: Vec<&[u8]> = __seeds.iter().map(|s| s.as_ref()).collect(); // [&[b"asdaasas"]]
+ let __seed_slices_array: &[&[u8]] = __seed_slices.as_slice();
let (__pda_address, __bump) = Pubkey::find_program_address(
- &[#maybe_seeds_plus_comma],
+ __seed_slices_array,
__program_id,
);
__bumps.#field = #bump;
#validate_pda
},
quote! {
- &[
- #maybe_seeds_plus_comma
- &[__bump][..]
- ][..]
+ &[__seed_slices_array, &[&[__bump]]].concat()[..]
},
)
}
@@ -1155,13 +1166,24 @@ fn generate_constraint_seeds(f: &Field, c: &ConstraintSeedsGroup) -> proc_macro2
// If the seeds came with a trailing comma, we need to chop it off
// before we interpolate them below.
- if let Some(pair) = s.pop() {
- s.push_value(pair.into_value());
+ match s {
+ SeedExpr::Puntuated(s) => {
+ if let Some(pair) = s.pop() {
+ s.push_value(pair.into_value());
+ }
+ }
+ _ => {}
}
- let maybe_seeds_plus_comma = (!s.is_empty()).then(|| {
- quote! { #s, }
- });
+ let seeds_defination = match s {
+ SeedExpr::Puntuated(s) => {
+ quote! { [#s] }
+ },
+ SeedExpr::Func(s) => {
+ quote! { #s }
+ }
+ };
+
let bump = if f.is_optional {
quote!(Some(__bump))
} else {
@@ -1172,16 +1194,18 @@ fn generate_constraint_seeds(f: &Field, c: &ConstraintSeedsGroup) -> proc_macro2
let define_pda = match c.bump.as_ref() {
// Bump target not given. Find it.
None => quote! {
+ let __seeds = #seeds_defination;
let (__pda_address, __bump) = Pubkey::find_program_address(
- &[#maybe_seeds_plus_comma],
+ &__seeds,
&#deriving_program_id,
);
__bumps.#name = #bump;
},
// Bump target given. Use it.
Some(b) => quote! {
+ let __seeds = #seeds_defination;
let __pda_address = Pubkey::create_program_address(
- &[#maybe_seeds_plus_comma &[#b][..]],
+ &__seeds,
&#deriving_program_id,
).map_err(|_| anchor_lang::error::Error::from(anchor_lang::error::ErrorCode::ConstraintSeeds).with_account_name(#name_str))?;
},
diff --git a/lang/syn/src/idl/accounts.rs b/lang/syn/src/idl/accounts.rs
index a66957bc..78049ad1 100644
--- a/lang/syn/src/idl/accounts.rs
+++ b/lang/syn/src/idl/accounts.rs
@@ -186,29 +186,30 @@ fn get_pda(acc: &Field, accounts: &AccountsStruct) -> TokenStream {
// Seeds
let seed_constraints = acc.constraints.seeds.as_ref();
- let pda = seed_constraints
- .map(|seed| seed.seeds.iter().map(parse_default))
- .and_then(|seeds| seeds.collect::<Result<Vec<_>>>().ok())
- .and_then(|seeds| {
- let program = match seed_constraints {
- Some(ConstraintSeedsGroup {
- program_seed: Some(program),
- ..
- }) => parse_default(program)
- .map(|program| quote! { Some(#program) })
- .ok()?,
- _ => quote! { None },
- };
-
- Some(quote! {
- Some(
- #idl::IdlPda {
- seeds: vec![#(#seeds),*],
- program: #program,
- }
- )
- })
- });
+ let pda = None;
+ // let pda = seed_constraints
+ // .map(|seed| seed.seeds.iter().map(parse_default))
+ // .and_then(|seeds| seeds.collect::<Result<Vec<_>>>().ok())
+ // .and_then(|seeds| {
+ // let program = match seed_constraints {
+ // Some(ConstraintSeedsGroup {
+ // program_seed: Some(program),
+ // ..
+ // }) => parse_default(program)
+ // .map(|program| quote! { Some(#program) })
+ // .ok()?,
+ // _ => quote! { None },
+ // };
+
+ // Some(quote! {
+ // Some(
+ // #idl::IdlPda {
+ // seeds: vec![#(#seeds),*],
+ // program: #program,
+ // }
+ // )
+ // })
+ // });
if let Some(pda) = pda {
return pda;
}
diff --git a/lang/syn/src/lib.rs b/lang/syn/src/lib.rs
index 33bc08b7..44751f4b 100644
--- a/lang/syn/src/lib.rs
+++ b/lang/syn/src/lib.rs
@@ -18,6 +18,7 @@ use parser::program as program_parser;
use proc_macro2::{Span, TokenStream};
use quote::quote;
use quote::ToTokens;
+use syn::ExprCall;
use std::collections::HashMap;
use std::ops::Deref;
use syn::ext::IdentExt;
@@ -881,9 +882,16 @@ pub struct ConstraintSeedsGroup {
pub program_seed: Option<Expr>, // None => use the current program's program_id.
}
+
+#[derive(Debug, Clone)]
+pub enum SeedExpr {
+ Puntuated(Punctuated<Expr, Token![,]>),
+ Func(ExprCall)
+}
+
#[derive(Debug, Clone)]
pub struct ConstraintSeeds {
- pub seeds: Punctuated<Expr, Token![,]>,
+ pub seeds: SeedExpr,
}
#[derive(Debug, Clone)]
diff --git a/lang/syn/src/parser/accounts/constraints.rs b/lang/syn/src/parser/accounts/constraints.rs
index 39617ea4..b83eeba6 100644
--- a/lang/syn/src/parser/accounts/constraints.rs
+++ b/lang/syn/src/parser/accounts/constraints.rs
@@ -1,6 +1,6 @@
use crate::*;
use syn::parse::{Error as ParseError, Result as ParseResult};
-use syn::{bracketed, Token};
+use syn::{bracketed, Token, parenthesized, braced};
pub fn parse(f: &syn::Field, f_ty: Option<&Ty>) -> ParseResult<ConstraintGroup> {
let mut constraints = ConstraintGroupBuilder::new(f_ty);
@@ -364,12 +364,40 @@ pub fn parse_token(stream: ParseStream) -> ParseResult<ConstraintToken> {
.span()
.join(stream.span())
.unwrap_or_else(|| ident.span());
- let seeds;
- let bracket = bracketed!(seeds in stream);
+
+ if stream.peek(syn::token::Bracket) {
+ let seeds;
+ let bracket = bracketed!(seeds in stream);
+ return Ok(ConstraintToken::Seeds(Context::new(
+ span.join(bracket.span).unwrap_or(span),
+ ConstraintSeeds {
+ seeds: SeedExpr::Puntuated(seeds.parse_terminated(Expr::parse)?),
+ },
+ )));
+ } else if stream.peek(syn::token::Paren) {
+ let seeds;
+ let paren = parenthesized!(seeds in stream);
+ return Ok(ConstraintToken::Seeds(Context::new(
+ span.join(paren.span).unwrap_or(span),
+ ConstraintSeeds {
+ seeds: SeedExpr::Puntuated(seeds.parse_terminated(Expr::parse)?),
+ },
+ )));
+ } else if stream.peek(syn::token::Brace) {
+ let seeds;
+ let brace = braced!(seeds in stream);
+ return Ok(ConstraintToken::Seeds(Context::new(
+ span.join(brace.span).unwrap_or(span),
+ ConstraintSeeds {
+ seeds: SeedExpr::Puntuated(seeds.parse_terminated(Expr::parse)?),
+ },
+ )))
+ }
+ let expr: ExprCall = stream.parse()?;
ConstraintToken::Seeds(Context::new(
- span.join(bracket.span).unwrap_or(span),
+ span,
ConstraintSeeds {
- seeds: seeds.parse_terminated(Expr::parse)?,
+ seeds: SeedExpr::Func(expr),
},
))
}