handlers.rs 29 KB

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