|
@@ -25,12 +25,54 @@ pub fn generate(program: Program) -> proc_macro2::TokenStream {
|
|
|
|
|
|
#[cfg(not(feature = "no-entrypoint"))]
|
|
|
anchor_lang::solana_program::entrypoint!(entry);
|
|
|
+ /// The Anchor codegen exposes a programming model where a user defines
|
|
|
+ /// a set of methods inside of a `#[program]` module in a way similar
|
|
|
+ /// to writing RPC request handlers. The macro then generates a bunch of
|
|
|
+ /// code wrapping these user defined methods into something that can be
|
|
|
+ /// executed on Solana.
|
|
|
+ ///
|
|
|
+ /// These methods fall into one of three categories, each of which
|
|
|
+ /// can be considered a different "namespace" of the program.
|
|
|
+ ///
|
|
|
+ /// 1) Global methods - regular methods inside of the `#[program]`.
|
|
|
+ /// 2) State methods - associated methods inside a `#[state]` struct.
|
|
|
+ /// 3) Interface methods - methods inside a strait struct's
|
|
|
+ /// implementation of an `#[interface]` trait.
|
|
|
+ ///
|
|
|
+ /// Care must be taken by the codegen to prevent collisions between
|
|
|
+ /// methods in these different namespaces. For this reason, Anchor uses
|
|
|
+ /// a variant of sighash to perform method dispatch, rather than
|
|
|
+ /// something like a simple enum variant discriminator.
|
|
|
+ ///
|
|
|
+ /// The execution flow of the generated code can be roughly outlined:
|
|
|
+ ///
|
|
|
+ /// * Start program via the entrypoint.
|
|
|
+ /// * Strip method identifier off the first 8 bytes of the instruction
|
|
|
+ /// data and invoke the identified method. The method identifier
|
|
|
+ /// is a variant of sighash. See docs.rs for `anchor_lang` for details.
|
|
|
+ /// * If the method identifier is an IDL identifier, execute the IDL
|
|
|
+ /// instructions, which are a special set of hardcoded instructions
|
|
|
+ /// baked into every Anchor program. Then exit.
|
|
|
+ /// * Otherwise, the method identifier is for a user defined
|
|
|
+ /// instruction, i.e., one of the methods in the user defined
|
|
|
+ /// `#[program]` module. Perform method dispatch, i.e., execute the
|
|
|
+ /// big match statement mapping method identifier to method handler
|
|
|
+ /// wrapper.
|
|
|
+ /// * Run the method handler wrapper. This wraps the code the user
|
|
|
+ /// actually wrote, deserializing the accounts, constructing the
|
|
|
+ /// context, invoking the user's code, and finally running the exit
|
|
|
+ /// routine, which typically persists account changes.
|
|
|
+ ///
|
|
|
+ /// The `entry` function here, defines the standard entry to a Solana
|
|
|
+ /// program, where execution begins.
|
|
|
#[cfg(not(feature = "no-entrypoint"))]
|
|
|
fn entry(program_id: &Pubkey, accounts: &[AccountInfo], ix_data: &[u8]) -> ProgramResult {
|
|
|
if ix_data.len() < 8 {
|
|
|
return Err(ProgramError::Custom(99));
|
|
|
}
|
|
|
|
|
|
+ // Split the instruction data into the first 8 byte method
|
|
|
+ // identifier (sighash) and the serialized instruction data.
|
|
|
let mut ix_data: &[u8] = ix_data;
|
|
|
let sighash: [u8; 8] = {
|
|
|
let mut sighash: [u8; 8] = [0; 8];
|
|
@@ -39,16 +81,14 @@ pub fn generate(program: Program) -> proc_macro2::TokenStream {
|
|
|
sighash
|
|
|
};
|
|
|
|
|
|
- if cfg!(not(feature = "no-idl")) {
|
|
|
- if sighash == anchor_lang::idl::IDL_IX_TAG.to_le_bytes() {
|
|
|
- return __private::__idl(program_id, accounts, &ix_data);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- #dispatch
|
|
|
+ dispatch(program_id, accounts, sighash, ix_data)
|
|
|
}
|
|
|
|
|
|
- // Create a private module to not clutter the program's namespace.
|
|
|
+ #dispatch
|
|
|
+
|
|
|
+ /// Create a private module to not clutter the program's namespace.
|
|
|
+ /// Defines an entrypoint for each individual instruction handler
|
|
|
+ /// wrapper.
|
|
|
mod __private {
|
|
|
use super::*;
|
|
|
|
|
@@ -81,10 +121,10 @@ pub fn generate_dispatch(program: &Program) -> proc_macro2::TokenStream {
|
|
|
format!("{:?}", sighash_arr).parse().unwrap();
|
|
|
quote! {
|
|
|
#sighash_tts => {
|
|
|
- let ix = instruction::#ix_name::deserialize(&mut ix_data)
|
|
|
+ let ix = instruction::state::#ix_name::deserialize(&mut ix_data)
|
|
|
.map_err(|_| ProgramError::Custom(1))?; // todo: error code
|
|
|
- let instruction::#variant_arm = ix;
|
|
|
- __private::__ctor(program_id, accounts, #(#ctor_args),*)
|
|
|
+ let instruction::state::#variant_arm = ix;
|
|
|
+ __private::__state::__ctor(program_id, accounts, #(#ctor_args),*)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -106,22 +146,18 @@ pub fn generate_dispatch(program: &Program) -> proc_macro2::TokenStream {
|
|
|
let name = &ix.raw_method.sig.ident.to_string();
|
|
|
let ix_method_name: proc_macro2::TokenStream =
|
|
|
{ format!("__{}", name).parse().unwrap() };
|
|
|
- let variant_arm = generate_ix_variant(
|
|
|
- ix.raw_method.sig.ident.to_string(),
|
|
|
- &ix.args,
|
|
|
- true,
|
|
|
- );
|
|
|
- let ix_name =
|
|
|
- generate_ix_variant_name(ix.raw_method.sig.ident.to_string(), true);
|
|
|
+ let variant_arm =
|
|
|
+ generate_ix_variant(ix.raw_method.sig.ident.to_string(), &ix.args);
|
|
|
+ let ix_name = generate_ix_variant_name(ix.raw_method.sig.ident.to_string());
|
|
|
let sighash_arr = sighash(SIGHASH_STATE_NAMESPACE, &name);
|
|
|
let sighash_tts: proc_macro2::TokenStream =
|
|
|
format!("{:?}", sighash_arr).parse().unwrap();
|
|
|
quote! {
|
|
|
#sighash_tts => {
|
|
|
- let ix = instruction::#ix_name::deserialize(&mut ix_data)
|
|
|
+ let ix = instruction::state::#ix_name::deserialize(&mut ix_data)
|
|
|
.map_err(|_| ProgramError::Custom(1))?; // todo: error code
|
|
|
- let instruction::#variant_arm = ix;
|
|
|
- __private::#ix_method_name(program_id, accounts, #(#ix_arg_names),*)
|
|
|
+ let instruction::state::#variant_arm = ix;
|
|
|
+ __private::__state::#ix_method_name(program_id, accounts, #(#ix_arg_names),*)
|
|
|
}
|
|
|
}
|
|
|
})
|
|
@@ -179,7 +215,7 @@ pub fn generate_dispatch(program: &Program) -> proc_macro2::TokenStream {
|
|
|
let Args {
|
|
|
#(#ix_arg_names),*
|
|
|
} = ix;
|
|
|
- __private::#ix_name(program_id, accounts, #(#ix_arg_names),*)
|
|
|
+ __private::__interface::#ix_name(program_id, accounts, #(#ix_arg_names),*)
|
|
|
}
|
|
|
}
|
|
|
})
|
|
@@ -191,38 +227,65 @@ pub fn generate_dispatch(program: &Program) -> proc_macro2::TokenStream {
|
|
|
};
|
|
|
|
|
|
// Dispatch all global instructions.
|
|
|
- let dispatch_arms: Vec<proc_macro2::TokenStream> = program
|
|
|
+ let global_dispatch_arms: Vec<proc_macro2::TokenStream> = program
|
|
|
.ixs
|
|
|
.iter()
|
|
|
.map(|ix| {
|
|
|
let ix_arg_names: Vec<&syn::Ident> = ix.args.iter().map(|arg| &arg.name).collect();
|
|
|
let ix_method_name = &ix.raw_method.sig.ident;
|
|
|
- let ix_name = generate_ix_variant_name(ix.raw_method.sig.ident.to_string(), false);
|
|
|
+ let ix_name = generate_ix_variant_name(ix.raw_method.sig.ident.to_string());
|
|
|
let sighash_arr = sighash(SIGHASH_GLOBAL_NAMESPACE, &ix_method_name.to_string());
|
|
|
let sighash_tts: proc_macro2::TokenStream =
|
|
|
format!("{:?}", sighash_arr).parse().unwrap();
|
|
|
- let variant_arm =
|
|
|
- generate_ix_variant(ix.raw_method.sig.ident.to_string(), &ix.args, false);
|
|
|
+ let variant_arm = generate_ix_variant(ix.raw_method.sig.ident.to_string(), &ix.args);
|
|
|
quote! {
|
|
|
#sighash_tts => {
|
|
|
let ix = instruction::#ix_name::deserialize(&mut ix_data)
|
|
|
.map_err(|_| ProgramError::Custom(1))?; // todo: error code
|
|
|
let instruction::#variant_arm = ix;
|
|
|
- __private::#ix_method_name(program_id, accounts, #(#ix_arg_names),*)
|
|
|
+ __private::__global::#ix_method_name(program_id, accounts, #(#ix_arg_names),*)
|
|
|
}
|
|
|
}
|
|
|
})
|
|
|
.collect();
|
|
|
|
|
|
quote! {
|
|
|
- match sighash {
|
|
|
- #ctor_state_dispatch_arm
|
|
|
- #(#state_dispatch_arms)*
|
|
|
- #(#trait_dispatch_arms)*
|
|
|
- #(#dispatch_arms)*
|
|
|
- _ => {
|
|
|
- msg!("Fallback functions are not supported. If you have a use case, please file an issue.");
|
|
|
- Err(ProgramError::Custom(99))
|
|
|
+ /// Performs method dispatch.
|
|
|
+ ///
|
|
|
+ /// Each method in an anchor program is uniquely defined by a namespace
|
|
|
+ /// and a rust identifier (i.e., the name given to the method). These
|
|
|
+ /// two pieces can be combined to creater a method identifier,
|
|
|
+ /// specifically, Anchor uses
|
|
|
+ ///
|
|
|
+ /// Sha256("<namespace>::<rust-identifier>")[..8],
|
|
|
+ ///
|
|
|
+ /// where the namespace can be one of three types. 1) "global" for a
|
|
|
+ /// regular instruction, 2) "state" for a state struct instruction
|
|
|
+ /// handler and 3) a trait namespace (used in combination with the
|
|
|
+ /// `#[interface]` attribute), which is defined by the trait name, e..
|
|
|
+ /// `MyTrait`.
|
|
|
+ ///
|
|
|
+ /// With this 8 byte identifier, Anchor performs method dispatch,
|
|
|
+ /// matching the given 8 byte identifier to the associated method
|
|
|
+ /// handler, which leads to user defined code being eventually invoked.
|
|
|
+ fn dispatch(program_id: &Pubkey, accounts: &[AccountInfo], sighash: [u8; 8], mut ix_data: &[u8]) -> ProgramResult {
|
|
|
+ // If the method identifier is the IDL tag, then execute an IDL
|
|
|
+ // instruction, injected into all Anchor programs.
|
|
|
+ if cfg!(not(feature = "no-idl")) {
|
|
|
+ if sighash == anchor_lang::idl::IDL_IX_TAG.to_le_bytes() {
|
|
|
+ return __private::__idl::__idl_dispatch(program_id, accounts, &ix_data);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ match sighash {
|
|
|
+ #ctor_state_dispatch_arm
|
|
|
+ #(#state_dispatch_arms)*
|
|
|
+ #(#trait_dispatch_arms)*
|
|
|
+ #(#global_dispatch_arms)*
|
|
|
+ _ => {
|
|
|
+ msg!("Fallback functions are not supported. If you have a use case, please file an issue.");
|
|
|
+ Err(ProgramError::Custom(99))
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -241,7 +304,7 @@ pub fn generate_non_inlined_handlers(program: &Program) -> proc_macro2::TokenStr
|
|
|
// on chain.
|
|
|
#[inline(never)]
|
|
|
#[cfg(not(feature = "no-idl"))]
|
|
|
- pub fn __idl(program_id: &Pubkey, accounts: &[AccountInfo], idl_ix_data: &[u8]) -> ProgramResult {
|
|
|
+ pub fn __idl_dispatch(program_id: &Pubkey, accounts: &[AccountInfo], idl_ix_data: &[u8]) -> ProgramResult {
|
|
|
let mut accounts = accounts;
|
|
|
let mut data: &[u8] = idl_ix_data;
|
|
|
|
|
@@ -280,7 +343,7 @@ pub fn generate_non_inlined_handlers(program: &Program) -> proc_macro2::TokenStr
|
|
|
|
|
|
#[inline(never)]
|
|
|
#[cfg(feature = "no-idl")]
|
|
|
- pub fn __idl(program_id: &Pubkey, accounts: &[AccountInfo], idl_ix_data: &[u8]) -> ProgramResult {
|
|
|
+ pub fn __idl_dispatch(program_id: &Pubkey, accounts: &[AccountInfo], idl_ix_data: &[u8]) -> ProgramResult {
|
|
|
Err(anchor_lang::solana_program::program_error::ProgramError::Custom(99))
|
|
|
}
|
|
|
|
|
@@ -658,11 +721,35 @@ pub fn generate_non_inlined_handlers(program: &Program) -> proc_macro2::TokenStr
|
|
|
.collect();
|
|
|
|
|
|
quote! {
|
|
|
- #non_inlined_idl
|
|
|
- #non_inlined_ctor
|
|
|
- #(#non_inlined_state_handlers)*
|
|
|
- #(#non_inlined_state_trait_handlers)*
|
|
|
- #(#non_inlined_handlers)*
|
|
|
+ /// __idl mod defines handlers for injected Anchor IDL instructions.
|
|
|
+ pub mod __idl {
|
|
|
+ use super::*;
|
|
|
+
|
|
|
+ #non_inlined_idl
|
|
|
+ }
|
|
|
+
|
|
|
+ /// __state mod defines wrapped handlers for state instructions.
|
|
|
+ pub mod __state {
|
|
|
+ use super::*;
|
|
|
+
|
|
|
+ #non_inlined_ctor
|
|
|
+ #(#non_inlined_state_handlers)*
|
|
|
+ }
|
|
|
+
|
|
|
+ /// __interface mod defines wrapped handlers for `#[interface]` trait
|
|
|
+ /// implementations.
|
|
|
+ pub mod __interface {
|
|
|
+ use super::*;
|
|
|
+
|
|
|
+ #(#non_inlined_state_trait_handlers)*
|
|
|
+ }
|
|
|
+
|
|
|
+ /// __global mod defines wrapped handlers for global instructions.
|
|
|
+ pub mod __global {
|
|
|
+ use super::*;
|
|
|
+
|
|
|
+ #(#non_inlined_handlers)*
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -683,36 +770,7 @@ pub fn generate_ctor_variant(state: &State) -> proc_macro2::TokenStream {
|
|
|
}
|
|
|
|
|
|
pub fn generate_ctor_variant_name() -> String {
|
|
|
- "__Ctor".to_string()
|
|
|
-}
|
|
|
-
|
|
|
-pub fn generate_ctor_typed_variant_with_semi(program: &Program) -> proc_macro2::TokenStream {
|
|
|
- match &program.state {
|
|
|
- None => quote! {},
|
|
|
- Some(state) => {
|
|
|
- let ctor_args: Vec<proc_macro2::TokenStream> = generate_ctor_typed_args(state)
|
|
|
- .iter()
|
|
|
- .map(|arg| {
|
|
|
- format!("pub {}", parser::tts_to_string(&arg))
|
|
|
- .parse()
|
|
|
- .unwrap()
|
|
|
- })
|
|
|
- .collect();
|
|
|
- if ctor_args.is_empty() {
|
|
|
- quote! {
|
|
|
- #[derive(AnchorSerialize, AnchorDeserialize)]
|
|
|
- pub struct __Ctor;
|
|
|
- }
|
|
|
- } else {
|
|
|
- quote! {
|
|
|
- #[derive(AnchorSerialize, AnchorDeserialize)]
|
|
|
- pub struct __Ctor {
|
|
|
- #(#ctor_args),*
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ "Ctor".to_string()
|
|
|
}
|
|
|
|
|
|
fn generate_ctor_typed_args(state: &State) -> Vec<syn::PatType> {
|
|
@@ -763,19 +821,11 @@ fn generate_ctor_args(state: &State) -> Vec<syn::Pat> {
|
|
|
.unwrap_or_default()
|
|
|
}
|
|
|
|
|
|
-pub fn generate_ix_variant(
|
|
|
- name: String,
|
|
|
- args: &[IxArg],
|
|
|
- underscore: bool,
|
|
|
-) -> proc_macro2::TokenStream {
|
|
|
+pub fn generate_ix_variant(name: String, args: &[IxArg]) -> proc_macro2::TokenStream {
|
|
|
let ix_arg_names: Vec<&syn::Ident> = args.iter().map(|arg| &arg.name).collect();
|
|
|
let ix_name_camel: proc_macro2::TokenStream = {
|
|
|
let n = name.to_camel_case();
|
|
|
- if underscore {
|
|
|
- format!("__{}", n).parse().unwrap()
|
|
|
- } else {
|
|
|
- n.parse().unwrap()
|
|
|
- }
|
|
|
+ n.parse().unwrap()
|
|
|
};
|
|
|
|
|
|
if args.is_empty() {
|
|
@@ -791,13 +841,9 @@ pub fn generate_ix_variant(
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-pub fn generate_ix_variant_name(name: String, underscore: bool) -> proc_macro2::TokenStream {
|
|
|
+pub fn generate_ix_variant_name(name: String) -> proc_macro2::TokenStream {
|
|
|
let n = name.to_camel_case();
|
|
|
- if underscore {
|
|
|
- format!("__{}", n).parse().unwrap()
|
|
|
- } else {
|
|
|
- n.parse().unwrap()
|
|
|
- }
|
|
|
+ n.parse().unwrap()
|
|
|
}
|
|
|
|
|
|
pub fn generate_methods(program: &Program) -> proc_macro2::TokenStream {
|
|
@@ -808,7 +854,50 @@ pub fn generate_methods(program: &Program) -> proc_macro2::TokenStream {
|
|
|
}
|
|
|
|
|
|
pub fn generate_ixs(program: &Program) -> proc_macro2::TokenStream {
|
|
|
- let ctor_variant = generate_ctor_typed_variant_with_semi(program);
|
|
|
+ let ctor_variant = match &program.state {
|
|
|
+ None => quote! {},
|
|
|
+ Some(state) => {
|
|
|
+ let ctor_args: Vec<proc_macro2::TokenStream> = generate_ctor_typed_args(state)
|
|
|
+ .iter()
|
|
|
+ .map(|arg| {
|
|
|
+ format!("pub {}", parser::tts_to_string(&arg))
|
|
|
+ .parse()
|
|
|
+ .unwrap()
|
|
|
+ })
|
|
|
+ .collect();
|
|
|
+ let strct = {
|
|
|
+ if ctor_args.is_empty() {
|
|
|
+ quote! {
|
|
|
+ #[derive(AnchorSerialize, AnchorDeserialize)]
|
|
|
+ pub struct Ctor;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ quote! {
|
|
|
+ #[derive(AnchorSerialize, AnchorDeserialize)]
|
|
|
+ pub struct Ctor {
|
|
|
+ #(#ctor_args),*
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ let sighash_arr = sighash_ctor();
|
|
|
+ let sighash_tts: proc_macro2::TokenStream =
|
|
|
+ format!("{:?}", sighash_arr).parse().unwrap();
|
|
|
+ quote! {
|
|
|
+ /// Instruction arguments to the `#[state]`'s `new`
|
|
|
+ /// constructor.
|
|
|
+ #strct
|
|
|
+
|
|
|
+ impl anchor_lang::InstructionData for Ctor {
|
|
|
+ fn data(&self) -> Vec<u8> {
|
|
|
+ let mut d = #sighash_tts.to_vec();
|
|
|
+ d.append(&mut self.try_to_vec().expect("Should always serialize"));
|
|
|
+ d
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
let state_method_variants: Vec<proc_macro2::TokenStream> = match &program.state {
|
|
|
None => vec![],
|
|
|
Some(state) => state
|
|
@@ -818,13 +907,14 @@ pub fn generate_ixs(program: &Program) -> proc_macro2::TokenStream {
|
|
|
methods
|
|
|
.iter()
|
|
|
.map(|method| {
|
|
|
- let ix_name_camel: proc_macro2::TokenStream = {
|
|
|
- let name = format!(
|
|
|
- "__{}",
|
|
|
- &method.raw_method.sig.ident.to_string().to_camel_case(),
|
|
|
- );
|
|
|
- name.parse().unwrap()
|
|
|
- };
|
|
|
+ let ix_name_camel: proc_macro2::TokenStream = method
|
|
|
+ .raw_method
|
|
|
+ .sig
|
|
|
+ .ident
|
|
|
+ .to_string()
|
|
|
+ .to_camel_case()
|
|
|
+ .parse()
|
|
|
+ .unwrap();
|
|
|
let raw_args: Vec<proc_macro2::TokenStream> = method
|
|
|
.args
|
|
|
.iter()
|
|
@@ -837,7 +927,7 @@ pub fn generate_ixs(program: &Program) -> proc_macro2::TokenStream {
|
|
|
|
|
|
let ix_data_trait = {
|
|
|
let name = method.raw_method.sig.ident.to_string();
|
|
|
- let sighash_arr = sighash(SIGHASH_GLOBAL_NAMESPACE, &name);
|
|
|
+ let sighash_arr = sighash(SIGHASH_STATE_NAMESPACE, &name);
|
|
|
let sighash_tts: proc_macro2::TokenStream =
|
|
|
format!("{:?}", sighash_arr).parse().unwrap();
|
|
|
quote! {
|
|
@@ -854,6 +944,7 @@ pub fn generate_ixs(program: &Program) -> proc_macro2::TokenStream {
|
|
|
// If no args, output a "unit" variant instead of a struct variant.
|
|
|
if method.args.is_empty() {
|
|
|
quote! {
|
|
|
+ /// Anchor generated instruction.
|
|
|
#[derive(AnchorSerialize, AnchorDeserialize)]
|
|
|
pub struct #ix_name_camel;
|
|
|
|
|
@@ -861,6 +952,7 @@ pub fn generate_ixs(program: &Program) -> proc_macro2::TokenStream {
|
|
|
}
|
|
|
} else {
|
|
|
quote! {
|
|
|
+ /// Anchor generated instruction.
|
|
|
#[derive(AnchorSerialize, AnchorDeserialize)]
|
|
|
pub struct #ix_name_camel {
|
|
|
#(#raw_args),*
|
|
@@ -907,6 +999,7 @@ pub fn generate_ixs(program: &Program) -> proc_macro2::TokenStream {
|
|
|
// If no args, output a "unit" variant instead of a struct variant.
|
|
|
if ix.args.is_empty() {
|
|
|
quote! {
|
|
|
+ /// Instruction.
|
|
|
#[derive(AnchorSerialize, AnchorDeserialize)]
|
|
|
pub struct #ix_name_camel;
|
|
|
|
|
@@ -914,6 +1007,7 @@ pub fn generate_ixs(program: &Program) -> proc_macro2::TokenStream {
|
|
|
}
|
|
|
} else {
|
|
|
quote! {
|
|
|
+ /// Instruction.
|
|
|
#[derive(AnchorSerialize, AnchorDeserialize)]
|
|
|
pub struct #ix_name_camel {
|
|
|
#(#raw_args),*
|
|
@@ -926,15 +1020,23 @@ pub fn generate_ixs(program: &Program) -> proc_macro2::TokenStream {
|
|
|
.collect();
|
|
|
|
|
|
quote! {
|
|
|
- /// `instruction` is a macro generated module containing the program's
|
|
|
- /// instruction enum, where each variant is created from each method
|
|
|
- /// handler in the `#[program]` mod. These should be used directly, when
|
|
|
- /// specifying instructions on a client.
|
|
|
+ /// An Anchor generated module containing the program's set of
|
|
|
+ /// instructions, where each method handler in the `#[program]` mod is
|
|
|
+ /// associated with a struct defining the input arguments to the
|
|
|
+ /// method. These should be used directly, when one wants to serialize
|
|
|
+ /// Anchor instruction data, for example, when speciying
|
|
|
+ /// instructions on a client.
|
|
|
pub mod instruction {
|
|
|
use super::*;
|
|
|
|
|
|
- #ctor_variant
|
|
|
- #(#state_method_variants)*
|
|
|
+ /// Instruction struct definitions for `#[state]` methods.
|
|
|
+ pub mod state {
|
|
|
+ use super::*;
|
|
|
+
|
|
|
+ #ctor_variant
|
|
|
+ #(#state_method_variants)*
|
|
|
+ }
|
|
|
+
|
|
|
#(#variants)*
|
|
|
}
|
|
|
}
|
|
@@ -984,7 +1086,7 @@ fn generate_accounts(program: &Program) -> proc_macro2::TokenStream {
|
|
|
// each struct here. This is convenient for Rust clients.
|
|
|
|
|
|
quote! {
|
|
|
- /// `accounts` is a macro generated module, providing a set of structs
|
|
|
+ /// An Anchor generated module, providing a set of structs
|
|
|
/// mirroring the structs deriving `Accounts`, where each field is
|
|
|
/// a `Pubkey`. This is useful for specifying accounts for a client.
|
|
|
pub mod accounts {
|
|
@@ -1000,8 +1102,7 @@ fn generate_cpi(program: &Program) -> proc_macro2::TokenStream {
|
|
|
.map(|ix| {
|
|
|
let accounts_ident = &ix.anchor_ident;
|
|
|
let cpi_method = {
|
|
|
- let ix_variant =
|
|
|
- generate_ix_variant(ix.raw_method.sig.ident.to_string(), &ix.args, false);
|
|
|
+ let ix_variant = generate_ix_variant(ix.raw_method.sig.ident.to_string(), &ix.args);
|
|
|
let method_name = &ix.ident;
|
|
|
let args: Vec<&syn::PatType> = ix.args.iter().map(|arg| &arg.raw_arg).collect();
|
|
|
let name = &ix.raw_method.sig.ident.to_string();
|