handlers.rs 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
  1. use crate::codegen::program::common::*;
  2. use crate::{Program, State};
  3. use heck::CamelCase;
  4. use quote::quote;
  5. // Generate non-inlined wrappers for each instruction handler, since Solana's
  6. // BPF max stack size can't handle reasonable sized dispatch trees without doing
  7. // so.
  8. pub fn generate(program: &Program) -> proc_macro2::TokenStream {
  9. let program_name = &program.name;
  10. let non_inlined_idl: proc_macro2::TokenStream = {
  11. quote! {
  12. // Entry for all IDL related instructions. Use the "no-idl" feature
  13. // to eliminate this code, for example, if one wants to make the
  14. // IDL no longer mutable or if one doesn't want to store the IDL
  15. // on chain.
  16. #[inline(never)]
  17. #[cfg(not(feature = "no-idl"))]
  18. pub fn __idl_dispatch(program_id: &Pubkey, accounts: &[AccountInfo], idl_ix_data: &[u8]) -> ProgramResult {
  19. let mut accounts = accounts;
  20. let mut data: &[u8] = idl_ix_data;
  21. let ix = anchor_lang::idl::IdlInstruction::deserialize(&mut data)
  22. .map_err(|_| anchor_lang::__private::ErrorCode::InstructionDidNotDeserialize)?;
  23. match ix {
  24. anchor_lang::idl::IdlInstruction::Create { data_len } => {
  25. let mut accounts =
  26. anchor_lang::idl::IdlCreateAccounts::try_accounts(program_id, &mut accounts, &[])?;
  27. __idl_create_account(program_id, &mut accounts, data_len)?;
  28. accounts.exit(program_id)?;
  29. },
  30. anchor_lang::idl::IdlInstruction::CreateBuffer => {
  31. let mut accounts =
  32. anchor_lang::idl::IdlCreateBuffer::try_accounts(program_id, &mut accounts, &[])?;
  33. __idl_create_buffer(program_id, &mut accounts)?;
  34. accounts.exit(program_id)?;
  35. },
  36. anchor_lang::idl::IdlInstruction::Write { data } => {
  37. let mut accounts =
  38. anchor_lang::idl::IdlAccounts::try_accounts(program_id, &mut accounts, &[])?;
  39. __idl_write(program_id, &mut accounts, data)?;
  40. accounts.exit(program_id)?;
  41. },
  42. anchor_lang::idl::IdlInstruction::SetAuthority { new_authority } => {
  43. let mut accounts =
  44. anchor_lang::idl::IdlAccounts::try_accounts(program_id, &mut accounts, &[])?;
  45. __idl_set_authority(program_id, &mut accounts, new_authority)?;
  46. accounts.exit(program_id)?;
  47. },
  48. anchor_lang::idl::IdlInstruction::SetBuffer => {
  49. let mut accounts =
  50. anchor_lang::idl::IdlSetBuffer::try_accounts(program_id, &mut accounts, &[])?;
  51. __idl_set_buffer(program_id, &mut accounts)?;
  52. accounts.exit(program_id)?;
  53. },
  54. }
  55. Ok(())
  56. }
  57. #[inline(never)]
  58. #[cfg(feature = "no-idl")]
  59. pub fn __idl_dispatch(program_id: &Pubkey, accounts: &[AccountInfo], idl_ix_data: &[u8]) -> ProgramResult {
  60. Err(anchor_lang::__private::ErrorCode::IdlInstructionStub.into())
  61. }
  62. // One time IDL account initializer. Will faill on subsequent
  63. // invocations.
  64. #[inline(never)]
  65. pub fn __idl_create_account(
  66. program_id: &Pubkey,
  67. accounts: &mut anchor_lang::idl::IdlCreateAccounts,
  68. data_len: u64,
  69. ) -> ProgramResult {
  70. #[cfg(not(feature = "no-log-ix-name"))]
  71. anchor_lang::prelude::msg!("Instruction: IdlCreateAccount");
  72. if program_id != accounts.program.key {
  73. return Err(anchor_lang::__private::ErrorCode::IdlInstructionInvalidProgram.into());
  74. }
  75. // Create the IDL's account.
  76. let from = accounts.from.key;
  77. let (base, nonce) = Pubkey::find_program_address(&[], program_id);
  78. let seed = anchor_lang::idl::IdlAccount::seed();
  79. let owner = accounts.program.key;
  80. let to = Pubkey::create_with_seed(&base, seed, owner).unwrap();
  81. // Space: account discriminator || authority pubkey || vec len || vec data
  82. let space = 8 + 32 + 4 + data_len as usize;
  83. let rent = Rent::get()?;
  84. let lamports = rent.minimum_balance(space);
  85. let seeds = &[&[nonce][..]];
  86. let ix = anchor_lang::solana_program::system_instruction::create_account_with_seed(
  87. from,
  88. &to,
  89. &base,
  90. seed,
  91. lamports,
  92. space as u64,
  93. owner,
  94. );
  95. anchor_lang::solana_program::program::invoke_signed(
  96. &ix,
  97. &[
  98. accounts.from.clone(),
  99. accounts.to.clone(),
  100. accounts.base.clone(),
  101. accounts.system_program.clone(),
  102. ],
  103. &[seeds],
  104. )?;
  105. // Deserialize the newly created account.
  106. let mut idl_account = {
  107. let mut account_data = accounts.to.try_borrow_data()?;
  108. let mut account_data_slice: &[u8] = &account_data;
  109. anchor_lang::idl::IdlAccount::try_deserialize_unchecked(
  110. &mut account_data_slice,
  111. )?
  112. };
  113. // Set the authority.
  114. idl_account.authority = *accounts.from.key;
  115. // Store the new account data.
  116. let mut data = accounts.to.try_borrow_mut_data()?;
  117. let dst: &mut [u8] = &mut data;
  118. let mut cursor = std::io::Cursor::new(dst);
  119. idl_account.try_serialize(&mut cursor)?;
  120. Ok(())
  121. }
  122. #[inline(never)]
  123. pub fn __idl_create_buffer(
  124. program_id: &Pubkey,
  125. accounts: &mut anchor_lang::idl::IdlCreateBuffer,
  126. ) -> ProgramResult {
  127. #[cfg(not(feature = "no-log-ix-name"))]
  128. anchor_lang::prelude::msg!("Instruction: IdlCreateBuffer");
  129. let mut buffer = &mut accounts.buffer;
  130. buffer.authority = *accounts.authority.key;
  131. Ok(())
  132. }
  133. #[inline(never)]
  134. pub fn __idl_write(
  135. program_id: &Pubkey,
  136. accounts: &mut anchor_lang::idl::IdlAccounts,
  137. idl_data: Vec<u8>,
  138. ) -> ProgramResult {
  139. #[cfg(not(feature = "no-log-ix-name"))]
  140. anchor_lang::prelude::msg!("Instruction: IdlWrite");
  141. let mut idl = &mut accounts.idl;
  142. idl.data.extend(idl_data);
  143. Ok(())
  144. }
  145. #[inline(never)]
  146. pub fn __idl_set_authority(
  147. program_id: &Pubkey,
  148. accounts: &mut anchor_lang::idl::IdlAccounts,
  149. new_authority: Pubkey,
  150. ) -> ProgramResult {
  151. #[cfg(not(feature = "no-log-ix-name"))]
  152. anchor_lang::prelude::msg!("Instruction: IdlSetAuthority");
  153. accounts.idl.authority = new_authority;
  154. Ok(())
  155. }
  156. #[inline(never)]
  157. pub fn __idl_set_buffer(
  158. program_id: &Pubkey,
  159. accounts: &mut anchor_lang::idl::IdlSetBuffer,
  160. ) -> ProgramResult {
  161. #[cfg(not(feature = "no-log-ix-name"))]
  162. anchor_lang::prelude::msg!("Instruction: IdlSetBuffer");
  163. accounts.idl.data = accounts.buffer.data.clone();
  164. Ok(())
  165. }
  166. }
  167. };
  168. // Constructor handler.
  169. let non_inlined_ctor: proc_macro2::TokenStream = match &program.state {
  170. None => quote! {},
  171. Some(state) => match state.ctor_and_anchor.as_ref() {
  172. None => quote! {},
  173. Some((_ctor, anchor_ident)) => {
  174. let ctor_untyped_args = generate_ctor_args(state);
  175. let name = &state.strct.ident;
  176. let mod_name = &program.name;
  177. let variant_arm = generate_ctor_variant(state);
  178. let ix_name: proc_macro2::TokenStream =
  179. generate_ctor_variant_name().parse().unwrap();
  180. let ix_name_log = format!("Instruction: {}", ix_name);
  181. if state.is_zero_copy {
  182. quote! {
  183. // One time state account initializer. Will faill on subsequent
  184. // invocations.
  185. #[inline(never)]
  186. pub fn __ctor(program_id: &Pubkey, accounts: &[AccountInfo], ix_data: &[u8]) -> ProgramResult {
  187. #[cfg(not(feature = "no-log-ix-name"))]
  188. anchor_lang::prelude::msg!(#ix_name_log);
  189. // Deserialize instruction data.
  190. let ix = instruction::state::#ix_name::deserialize(&mut &ix_data[..])
  191. .map_err(|_| anchor_lang::__private::ErrorCode::InstructionDidNotDeserialize)?;
  192. let instruction::state::#variant_arm = ix;
  193. // Deserialize accounts.
  194. let mut remaining_accounts: &[AccountInfo] = accounts;
  195. let ctor_accounts = anchor_lang::__private::Ctor::try_accounts(program_id, &mut remaining_accounts, &[])?;
  196. let mut ctor_user_def_accounts = #anchor_ident::try_accounts(program_id, &mut remaining_accounts, ix_data)?;
  197. // Create the solana account for the ctor data.
  198. let from = ctor_accounts.from.key;
  199. let (base, nonce) = Pubkey::find_program_address(&[], ctor_accounts.program.key);
  200. let seed = anchor_lang::__private::PROGRAM_STATE_SEED;
  201. let owner = ctor_accounts.program.key;
  202. let to = Pubkey::create_with_seed(&base, seed, owner).unwrap();
  203. let space = 8 + std::mem::size_of::<#name>();
  204. let rent = Rent::get()?;
  205. let lamports = rent.minimum_balance(std::convert::TryInto::try_into(space).unwrap());
  206. let seeds = &[&[nonce][..]];
  207. let ix = anchor_lang::solana_program::system_instruction::create_account_with_seed(
  208. from,
  209. &to,
  210. &base,
  211. seed,
  212. lamports,
  213. space as u64,
  214. owner,
  215. );
  216. anchor_lang::solana_program::program::invoke_signed(
  217. &ix,
  218. &[
  219. ctor_accounts.from.clone(),
  220. ctor_accounts.to.clone(),
  221. ctor_accounts.base.clone(),
  222. ctor_accounts.system_program.clone(),
  223. ],
  224. &[seeds],
  225. )?;
  226. // Zero copy deserialize.
  227. let loader: anchor_lang::Loader<#mod_name::#name> = anchor_lang::Loader::try_from_unchecked(program_id, &ctor_accounts.to)?;
  228. // Invoke the ctor in a new lexical scope so that
  229. // the zero-copy RefMut gets dropped. Required
  230. // so that we can subsequently run the exit routine.
  231. {
  232. let mut instance = loader.load_init()?;
  233. instance.new(
  234. anchor_lang::Context::new(
  235. program_id,
  236. &mut ctor_user_def_accounts,
  237. remaining_accounts,
  238. ),
  239. #(#ctor_untyped_args),*
  240. )?;
  241. }
  242. // Exit routines.
  243. ctor_user_def_accounts.exit(program_id)?;
  244. loader.exit(program_id)?;
  245. Ok(())
  246. }
  247. }
  248. } else {
  249. quote! {
  250. // One time state account initializer. Will faill on subsequent
  251. // invocations.
  252. #[inline(never)]
  253. pub fn __ctor(program_id: &Pubkey, accounts: &[AccountInfo], ix_data: &[u8]) -> ProgramResult {
  254. #[cfg(not(feature = "no-log-ix-name"))]
  255. anchor_lang::prelude::msg!(#ix_name_log);
  256. // Deserialize instruction data.
  257. let ix = instruction::state::#ix_name::deserialize(&mut &ix_data[..])
  258. .map_err(|_| anchor_lang::__private::ErrorCode::InstructionDidNotDeserialize)?;
  259. let instruction::state::#variant_arm = ix;
  260. // Deserialize accounts.
  261. let mut remaining_accounts: &[AccountInfo] = accounts;
  262. let ctor_accounts = anchor_lang::__private::Ctor::try_accounts(program_id, &mut remaining_accounts, &[])?;
  263. let mut ctor_user_def_accounts = #anchor_ident::try_accounts(program_id, &mut remaining_accounts, ix_data)?;
  264. // Invoke the ctor.
  265. let instance = #mod_name::#name::new(
  266. anchor_lang::Context::new(
  267. program_id,
  268. &mut ctor_user_def_accounts,
  269. remaining_accounts,
  270. ),
  271. #(#ctor_untyped_args),*
  272. )?;
  273. // Create the solana account for the ctor data.
  274. let from = ctor_accounts.from.key;
  275. let (base, nonce) = Pubkey::find_program_address(&[], ctor_accounts.program.key);
  276. let seed = anchor_lang::ProgramState::<#name>::seed();
  277. let owner = ctor_accounts.program.key;
  278. let to = Pubkey::create_with_seed(&base, seed, owner).unwrap();
  279. let space = anchor_lang::__private::AccountSize::size(&instance)?;
  280. let rent = Rent::get()?;
  281. let lamports = rent.minimum_balance(std::convert::TryInto::try_into(space).unwrap());
  282. let seeds = &[&[nonce][..]];
  283. let ix = anchor_lang::solana_program::system_instruction::create_account_with_seed(
  284. from,
  285. &to,
  286. &base,
  287. seed,
  288. lamports,
  289. space,
  290. owner,
  291. );
  292. anchor_lang::solana_program::program::invoke_signed(
  293. &ix,
  294. &[
  295. ctor_accounts.from.clone(),
  296. ctor_accounts.to.clone(),
  297. ctor_accounts.base.clone(),
  298. ctor_accounts.system_program.clone(),
  299. ],
  300. &[seeds],
  301. )?;
  302. // Serialize the state and save it to storage.
  303. ctor_user_def_accounts.exit(program_id)?;
  304. let mut data = ctor_accounts.to.try_borrow_mut_data()?;
  305. let dst: &mut [u8] = &mut data;
  306. let mut cursor = std::io::Cursor::new(dst);
  307. instance.try_serialize(&mut cursor)?;
  308. Ok(())
  309. }
  310. }
  311. }
  312. }
  313. },
  314. };
  315. // State method handlers.
  316. let non_inlined_state_handlers: Vec<proc_macro2::TokenStream> = match &program.state {
  317. None => vec![],
  318. Some(state) => state
  319. .impl_block_and_methods
  320. .as_ref()
  321. .map(|(_impl_block, methods)| {
  322. methods
  323. .iter()
  324. .map(|ix| {
  325. let ix_arg_names: Vec<&syn::Ident> =
  326. ix.args.iter().map(|arg| &arg.name).collect();
  327. let private_ix_method_name: proc_macro2::TokenStream = {
  328. let n = format!("__{}", &ix.raw_method.sig.ident.to_string());
  329. n.parse().unwrap()
  330. };
  331. let ix_method_name = &ix.raw_method.sig.ident;
  332. let state_ty: proc_macro2::TokenStream = state.name.parse().unwrap();
  333. let anchor_ident = &ix.anchor_ident;
  334. let name = &state.strct.ident;
  335. let mod_name = &program.name;
  336. let variant_arm =
  337. generate_ix_variant(ix.raw_method.sig.ident.to_string(), &ix.args);
  338. let ix_name = generate_ix_variant_name(ix.raw_method.sig.ident.to_string());
  339. let ix_name_log = format!("Instruction: {}", ix_name);
  340. if state.is_zero_copy {
  341. quote! {
  342. #[inline(never)]
  343. pub fn #private_ix_method_name(
  344. program_id: &Pubkey,
  345. accounts: &[AccountInfo],
  346. ix_data: &[u8],
  347. ) -> ProgramResult {
  348. #[cfg(not(feature = "no-log-ix-name"))]
  349. anchor_lang::prelude::msg!(#ix_name_log);
  350. // Deserialize instruction.
  351. let ix = instruction::state::#ix_name::deserialize(&mut &ix_data[..])
  352. .map_err(|_| anchor_lang::__private::ErrorCode::InstructionDidNotDeserialize)?;
  353. let instruction::state::#variant_arm = ix;
  354. // Load state.
  355. let mut remaining_accounts: &[AccountInfo] = accounts;
  356. if remaining_accounts.is_empty() {
  357. return Err(anchor_lang::__private::ErrorCode::AccountNotEnoughKeys.into());
  358. }
  359. let loader: anchor_lang::Loader<#mod_name::#name> = anchor_lang::Loader::try_accounts(program_id, &mut remaining_accounts, &[])?;
  360. // Deserialize accounts.
  361. let mut accounts = #anchor_ident::try_accounts(
  362. program_id,
  363. &mut remaining_accounts,
  364. ix_data,
  365. )?;
  366. let ctx = Context::new(program_id, &mut accounts, remaining_accounts);
  367. // Execute user defined function.
  368. {
  369. let mut state = loader.load_mut()?;
  370. state.#ix_method_name(
  371. ctx,
  372. #(#ix_arg_names),*
  373. )?;
  374. }
  375. // Serialize the state and save it to storage.
  376. accounts.exit(program_id)?;
  377. loader.exit(program_id)?;
  378. Ok(())
  379. }
  380. }
  381. } else {
  382. quote! {
  383. #[inline(never)]
  384. pub fn #private_ix_method_name(
  385. program_id: &Pubkey,
  386. accounts: &[AccountInfo],
  387. ix_data: &[u8],
  388. ) -> ProgramResult {
  389. #[cfg(not(feature = "no-log-ix-name"))]
  390. anchor_lang::prelude::msg!(#ix_name_log);
  391. // Deserialize instruction.
  392. let ix = instruction::state::#ix_name::deserialize(&mut &ix_data[..])
  393. .map_err(|_| anchor_lang::__private::ErrorCode::InstructionDidNotDeserialize)?;
  394. let instruction::state::#variant_arm = ix;
  395. // Load state.
  396. let mut remaining_accounts: &[AccountInfo] = accounts;
  397. if remaining_accounts.is_empty() {
  398. return Err(anchor_lang::__private::ErrorCode::AccountNotEnoughKeys.into());
  399. }
  400. let mut state: anchor_lang::ProgramState<#state_ty> = anchor_lang::ProgramState::try_accounts(program_id, &mut remaining_accounts, &[])?;
  401. // Deserialize accounts.
  402. let mut accounts = #anchor_ident::try_accounts(
  403. program_id,
  404. &mut remaining_accounts,
  405. ix_data,
  406. )?;
  407. let ctx = Context::new(program_id, &mut accounts, remaining_accounts);
  408. // Execute user defined function.
  409. state.#ix_method_name(
  410. ctx,
  411. #(#ix_arg_names),*
  412. )?;
  413. // Serialize the state and save it to storage.
  414. accounts.exit(program_id)?;
  415. let acc_info = state.to_account_info();
  416. let mut data = acc_info.try_borrow_mut_data()?;
  417. let dst: &mut [u8] = &mut data;
  418. let mut cursor = std::io::Cursor::new(dst);
  419. state.try_serialize(&mut cursor)?;
  420. Ok(())
  421. }
  422. }
  423. }
  424. })
  425. .collect()
  426. })
  427. .unwrap_or_default(),
  428. };
  429. // State trait handlers.
  430. let non_inlined_state_trait_handlers: Vec<proc_macro2::TokenStream> = match &program.state {
  431. None => Vec::new(),
  432. Some(state) => state
  433. .interfaces
  434. .as_ref()
  435. .map(|interfaces| {
  436. interfaces
  437. .iter()
  438. .flat_map(|iface: &crate::StateInterface| {
  439. iface
  440. .methods
  441. .iter()
  442. .map(|ix| {
  443. if state.is_zero_copy {
  444. // Easy to implement. Just need to write a test.
  445. // Feel free to open a PR.
  446. panic!("Trait implementations not yet implemented for zero copy state structs. Please file an issue.");
  447. }
  448. let ix_arg_names: Vec<&syn::Ident> =
  449. ix.args.iter().map(|arg| &arg.name).collect();
  450. let private_ix_method_name: proc_macro2::TokenStream = {
  451. let n = format!("__{}_{}", iface.trait_name, &ix.raw_method.sig.ident.to_string());
  452. n.parse().unwrap()
  453. };
  454. let ix_method_name = &ix.raw_method.sig.ident;
  455. let state_ty: proc_macro2::TokenStream = state.name.parse().unwrap();
  456. let anchor_ident = &ix.anchor_ident;
  457. let ix_name = generate_ix_variant_name(ix.raw_method.sig.ident.to_string());
  458. let ix_name_log = format!("Instruction: {}", ix_name);
  459. let raw_args: Vec<&syn::PatType> = ix
  460. .args
  461. .iter()
  462. .map(|arg: &crate::IxArg| &arg.raw_arg)
  463. .collect();
  464. let args_struct = {
  465. if ix.args.is_empty() {
  466. quote! {
  467. #[derive(anchor_lang::AnchorSerialize, anchor_lang::AnchorDeserialize)]
  468. struct Args;
  469. }
  470. } else {
  471. quote! {
  472. #[derive(anchor_lang::AnchorSerialize, anchor_lang::AnchorDeserialize)]
  473. struct Args {
  474. #(#raw_args),*
  475. }
  476. }
  477. }
  478. };
  479. let deserialize_instruction = quote! {
  480. #args_struct
  481. let ix = Args::deserialize(&mut &ix_data[..])
  482. .map_err(|_| anchor_lang::__private::ErrorCode::InstructionDidNotDeserialize)?;
  483. let Args {
  484. #(#ix_arg_names),*
  485. } = ix;
  486. };
  487. if ix.has_receiver {
  488. quote! {
  489. #[inline(never)]
  490. pub fn #private_ix_method_name(
  491. program_id: &Pubkey,
  492. accounts: &[AccountInfo],
  493. ix_data: &[u8],
  494. ) -> ProgramResult {
  495. #[cfg(not(feature = "no-log-ix-name"))]
  496. anchor_lang::prelude::msg!(#ix_name_log);
  497. // Deserialize instruction.
  498. #deserialize_instruction
  499. // Deserialize the program state account.
  500. let mut remaining_accounts: &[AccountInfo] = accounts;
  501. if remaining_accounts.is_empty() {
  502. return Err(anchor_lang::__private::ErrorCode::AccountNotEnoughKeys.into());
  503. }
  504. let mut state: anchor_lang::ProgramState<#state_ty> = anchor_lang::ProgramState::try_accounts(program_id, &mut remaining_accounts, &[])?;
  505. // Deserialize accounts.
  506. let mut accounts = #anchor_ident::try_accounts(
  507. program_id,
  508. &mut remaining_accounts,
  509. ix_data,
  510. )?;
  511. let ctx = Context::new(program_id, &mut accounts, remaining_accounts);
  512. // Execute user defined function.
  513. state.#ix_method_name(
  514. ctx,
  515. #(#ix_arg_names),*
  516. )?;
  517. // Exit procedures.
  518. accounts.exit(program_id)?;
  519. let acc_info = state.to_account_info();
  520. let mut data = acc_info.try_borrow_mut_data()?;
  521. let dst: &mut [u8] = &mut data;
  522. let mut cursor = std::io::Cursor::new(dst);
  523. state.try_serialize(&mut cursor)?;
  524. Ok(())
  525. }
  526. }
  527. } else {
  528. let state_name: proc_macro2::TokenStream = state.name.parse().unwrap();
  529. quote! {
  530. #[inline(never)]
  531. pub fn #private_ix_method_name(
  532. program_id: &Pubkey,
  533. accounts: &[AccountInfo],
  534. ix_data: &[u8],
  535. ) -> ProgramResult {
  536. #[cfg(not(feature = "no-log-ix-name"))]
  537. anchor_lang::prelude::msg!(#ix_name_log);
  538. // Deserialize instruction.
  539. #deserialize_instruction
  540. // Deserialize accounts.
  541. let mut remaining_accounts: &[AccountInfo] = accounts;
  542. let mut accounts = #anchor_ident::try_accounts(
  543. program_id,
  544. &mut remaining_accounts,
  545. ix_data,
  546. )?;
  547. // Execute user defined function.
  548. #state_name::#ix_method_name(
  549. Context::new(program_id, &mut accounts, remaining_accounts),
  550. #(#ix_arg_names),*
  551. )?;
  552. // Exit procedure.
  553. accounts.exit(program_id)
  554. }
  555. }
  556. }
  557. })
  558. .collect::<Vec<proc_macro2::TokenStream>>()
  559. })
  560. .collect()
  561. })
  562. .unwrap_or_default(),
  563. };
  564. let non_inlined_handlers: Vec<proc_macro2::TokenStream> = program
  565. .ixs
  566. .iter()
  567. .map(|ix| {
  568. let ix_arg_names: Vec<&syn::Ident> = ix.args.iter().map(|arg| &arg.name).collect();
  569. let ix_name = generate_ix_variant_name(ix.raw_method.sig.ident.to_string());
  570. let ix_method_name = &ix.raw_method.sig.ident;
  571. let anchor = &ix.anchor_ident;
  572. let variant_arm = generate_ix_variant(ix.raw_method.sig.ident.to_string(), &ix.args);
  573. let ix_name_log = format!("Instruction: {}", ix_name);
  574. quote! {
  575. #[inline(never)]
  576. pub fn #ix_method_name(
  577. program_id: &Pubkey,
  578. accounts: &[AccountInfo],
  579. ix_data: &[u8],
  580. ) -> ProgramResult {
  581. #[cfg(not(feature = "no-log-ix-name"))]
  582. anchor_lang::prelude::msg!(#ix_name_log);
  583. // Deserialize data.
  584. let ix = instruction::#ix_name::deserialize(&mut &ix_data[..])
  585. .map_err(|_| anchor_lang::__private::ErrorCode::InstructionDidNotDeserialize)?;
  586. let instruction::#variant_arm = ix;
  587. // Deserialize accounts.
  588. let mut remaining_accounts: &[AccountInfo] = accounts;
  589. let mut accounts = #anchor::try_accounts(
  590. program_id,
  591. &mut remaining_accounts,
  592. ix_data,
  593. )?;
  594. // Invoke user defined handler.
  595. #program_name::#ix_method_name(
  596. Context::new(program_id, &mut accounts, remaining_accounts),
  597. #(#ix_arg_names),*
  598. )?;
  599. // Exit routine.
  600. accounts.exit(program_id)
  601. }
  602. }
  603. })
  604. .collect();
  605. quote! {
  606. /// Create a private module to not clutter the program's namespace.
  607. /// Defines an entrypoint for each individual instruction handler
  608. /// wrapper.
  609. mod __private {
  610. use super::*;
  611. /// __idl mod defines handlers for injected Anchor IDL instructions.
  612. pub mod __idl {
  613. use super::*;
  614. #non_inlined_idl
  615. }
  616. /// __state mod defines wrapped handlers for state instructions.
  617. pub mod __state {
  618. use super::*;
  619. #non_inlined_ctor
  620. #(#non_inlined_state_handlers)*
  621. }
  622. /// __interface mod defines wrapped handlers for `#[interface]` trait
  623. /// implementations.
  624. pub mod __interface {
  625. use super::*;
  626. #(#non_inlined_state_trait_handlers)*
  627. }
  628. /// __global mod defines wrapped handlers for global instructions.
  629. pub mod __global {
  630. use super::*;
  631. #(#non_inlined_handlers)*
  632. }
  633. }
  634. }
  635. }
  636. fn generate_ix_variant_name(name: String) -> proc_macro2::TokenStream {
  637. let n = name.to_camel_case();
  638. n.parse().unwrap()
  639. }
  640. fn generate_ctor_variant_name() -> String {
  641. "New".to_string()
  642. }
  643. fn generate_ctor_variant(state: &State) -> proc_macro2::TokenStream {
  644. let ctor_args = generate_ctor_args(state);
  645. let ctor_variant_name: proc_macro2::TokenStream = generate_ctor_variant_name().parse().unwrap();
  646. if ctor_args.is_empty() {
  647. quote! {
  648. #ctor_variant_name
  649. }
  650. } else {
  651. quote! {
  652. #ctor_variant_name {
  653. #(#ctor_args),*
  654. }
  655. }
  656. }
  657. }