solana_program/
entrypoint_deprecated.rs

1//! The Rust-based BPF program entrypoint supported by the original BPF loader.
2//!
3//! The original BPF loader is deprecated and exists for backwards-compatibility
4//! reasons. This module should not be used by new programs.
5//!
6//! For more information see the [`bpf_loader_deprecated`] module.
7//!
8//! [`bpf_loader_deprecated`]: crate::bpf_loader_deprecated
9
10#![allow(clippy::arithmetic_side_effects)]
11
12extern crate alloc;
13use {
14    crate::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey},
15    alloc::vec::Vec,
16    std::{
17        mem::size_of,
18        result::Result as ResultGeneric,
19        slice::{from_raw_parts, from_raw_parts_mut},
20    },
21};
22
23pub type ProgramResult = ResultGeneric<(), ProgramError>;
24
25/// User implemented function to process an instruction
26///
27/// program_id: Program ID of the currently executing program
28/// accounts: Accounts passed as part of the instruction
29/// instruction_data: Instruction data
30pub type ProcessInstruction =
31    fn(program_id: &Pubkey, accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult;
32
33/// Programs indicate success with a return value of 0
34pub const SUCCESS: u64 = 0;
35
36/// Declare the program entrypoint.
37///
38/// Deserialize the program input arguments and call
39/// the user defined `process_instruction` function.
40/// Users must call this macro otherwise an entrypoint for
41/// their program will not be created.
42#[macro_export]
43macro_rules! entrypoint_deprecated {
44    ($process_instruction:ident) => {
45        /// # Safety
46        #[no_mangle]
47        pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 {
48            let (program_id, accounts, instruction_data) =
49                unsafe { $crate::entrypoint_deprecated::deserialize(input) };
50            match $process_instruction(&program_id, &accounts, &instruction_data) {
51                Ok(()) => $crate::entrypoint_deprecated::SUCCESS,
52                Err(error) => error.into(),
53            }
54        }
55    };
56}
57
58/// Deserialize the input arguments
59///
60/// # Safety
61#[allow(clippy::type_complexity)]
62pub unsafe fn deserialize<'a>(input: *mut u8) -> (&'a Pubkey, Vec<AccountInfo<'a>>, &'a [u8]) {
63    let mut offset: usize = 0;
64
65    // Number of accounts present
66
67    #[allow(clippy::cast_ptr_alignment)]
68    let num_accounts = *(input.add(offset) as *const u64) as usize;
69    offset += size_of::<u64>();
70
71    // Account Infos
72
73    let mut accounts = Vec::with_capacity(num_accounts);
74    for _ in 0..num_accounts {
75        let dup_info = *(input.add(offset) as *const u8);
76        offset += size_of::<u8>();
77        if dup_info == u8::MAX {
78            #[allow(clippy::cast_ptr_alignment)]
79            let is_signer = *(input.add(offset) as *const u8) != 0;
80            offset += size_of::<u8>();
81
82            #[allow(clippy::cast_ptr_alignment)]
83            let is_writable = *(input.add(offset) as *const u8) != 0;
84            offset += size_of::<u8>();
85
86            let key: &Pubkey = &*(input.add(offset) as *const Pubkey);
87            offset += size_of::<Pubkey>();
88
89            #[allow(clippy::cast_ptr_alignment)]
90            let lamports = &mut *(input.add(offset) as *mut u64);
91            offset += size_of::<u64>();
92
93            #[allow(clippy::cast_ptr_alignment)]
94            let data_len = *(input.add(offset) as *const u64) as usize;
95            offset += size_of::<u64>();
96
97            let data = from_raw_parts_mut(input.add(offset), data_len);
98            offset += data_len;
99
100            let owner: &Pubkey = &*(input.add(offset) as *const Pubkey);
101            offset += size_of::<Pubkey>();
102
103            #[allow(clippy::cast_ptr_alignment)]
104            let executable = *(input.add(offset) as *const u8) != 0;
105            offset += size_of::<u8>();
106
107            // rent epoch is skipped
108            offset += size_of::<u64>();
109
110            accounts.push(AccountInfo::new(
111                key,
112                is_signer,
113                is_writable,
114                lamports,
115                data,
116                owner,
117                executable,
118            ));
119        } else {
120            // Duplicate account, clone the original
121            accounts.push(accounts[dup_info as usize].clone());
122        }
123    }
124
125    // Instruction data
126
127    #[allow(clippy::cast_ptr_alignment)]
128    let instruction_data_len = *(input.add(offset) as *const u64) as usize;
129    offset += size_of::<u64>();
130
131    let instruction_data = { from_raw_parts(input.add(offset), instruction_data_len) };
132    offset += instruction_data_len;
133
134    // Program Id
135
136    let program_id: &Pubkey = &*(input.add(offset) as *const Pubkey);
137
138    (program_id, accounts, instruction_data)
139}