nitrate/
lib.rs

1#![allow(clippy::missing_safety_doc)]
2
3extern crate nitrate_macro;
4pub use nitrate_macro::*;
5
6pub mod program {
7    pub use nitrate_program::*;
8}
9
10/// Declare the program entrypoint and set up global handlers.
11///
12/// The main difference from the standard `entrypoint!` macro is that this macro represents an
13/// entrypoint that does not perform allocattions or copies when reading the input buffer.
14///
15/// This macro emits the common boilerplate necessary to begin program execution, calling a
16/// provided function to process the program instruction supplied by the runtime, and reporting
17/// its result to the runtime.
18///
19/// It also sets up a [global allocator] and [panic handler], using the [`custom_heap_default`]
20/// and [`custom_panic_default`] macros from the [`solana_program`] crate.
21///
22/// [`custom_heap_default`]: https://docs.rs/solana-program/latest/solana_program/macro.custom_heap_default.html
23/// [`custom_panic_default`]: https://docs.rs/solana-program/latest/solana_program/macro.custom_panic_default.html
24/// [`solana_program`]: https://docs.rs/solana-program/latest/solana_program/index.html
25///
26/// The first argument is the name of a function with this type signature:
27///
28/// ```ignore
29/// fn process_instruction(
30///     program_id: &Pubkey,      // Public key of the account the program was loaded into
31///     accounts: &[AccountInfo], // All accounts required to process the instruction
32///     instruction_data: &[u8],  // Serialized instruction-specific data
33/// ) -> ProgramResult;
34/// ```
35///
36/// The second argument is the maximum number of accounts that the program is expecting. A program
37/// can receive more than the specified maximum, but any account exceeding the maximum will be
38/// ignored.
39///
40/// # Examples
41///
42/// Defining an entrypoint which reads up to 10 accounts and making it conditional on the
43/// `no-entrypoint` feature. Although the `entrypoint` module is written inline in this example,
44/// it is common to put it into its own file.
45///
46/// ```no_run
47/// #[cfg(not(feature = "no-entrypoint"))]
48/// pub mod entrypoint {
49///
50///     use nitrate::{entrypoint, program::AccountInfo};
51///     use solana_program::{
52///         entrypoint::ProgramResult,
53///         msg,
54///         pubkey::Pubkey,
55///     };
56///
57///     entrypoint!(process_instruction, 10);
58///
59///     pub fn process_instruction(
60///         program_id: &Pubkey,
61///         accounts: &[AccountInfo],
62///         instruction_data: &[u8],
63///     ) -> ProgramResult {
64///         msg!("Hello from my program!");
65///
66///         Ok(())
67///     }
68///
69/// }
70/// ```
71#[macro_export]
72macro_rules! entrypoint {
73    ( $process_instruction:ident, $maximum:literal ) => {
74        #[no_mangle]
75        pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 {
76            // create an array of uninitialized account infos; it is safe to `assume_init` since
77            // we are claiming that the aray of `MaybeUninit` is initialized and `MaybeUniint` do
78            // not require initialization
79            let mut accounts: [std::mem::MaybeUninit<$crate::program::AccountInfo>; $maximum] =
80                std::mem::MaybeUninit::uninit().assume_init();
81
82            let (program_id, count, instruction_data) =
83                $crate::program::deserialize::<$maximum>(input, accounts.as_mut_ptr());
84
85            // call the program's entrypoint passing `count` account infos; we know that
86            // they are initialized so we cast the pointer to a slice of `[AccountInfo]`
87            match $process_instruction(
88                &program_id,
89                std::slice::from_raw_parts(accounts.as_ptr() as _, count),
90                &instruction_data,
91            ) {
92                Ok(()) => solana_program::entrypoint::SUCCESS,
93                Err(error) => error.into(),
94            }
95        }
96
97        solana_program::custom_heap_default!();
98        solana_program::custom_panic_default!();
99    };
100}