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