1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
//! @brief Solana Rust-based BPF program entrypoint and its parameter types

extern crate alloc;

use crate::{account_info::AccountInfo, pubkey::Pubkey};
use alloc::vec::Vec;
use core::mem::size_of;
use core::slice::{from_raw_parts, from_raw_parts_mut};

/// User implemented program entrypoint
///
/// program_id: Program ID of the currently executing program
/// accounts: Accounts passed as part of the instruction
/// data: Instruction data
pub type ProcessInstruction =
    fn(program_id: &Pubkey, accounts: &mut [AccountInfo], data: &[u8]) -> bool;

/// Programs indicate success with a return value of 0
pub const SUCCESS: u32 = 0;

/// Declare entrypoint of the program.
///
/// Deserialize the program input parameters and call
/// the user defined `ProcessInstruction`.  Users must call
/// this function otherwise an entrypoint for
/// their program will not be created.
#[macro_export]
macro_rules! entrypoint {
    ($process_instruction:ident) => {
        #[no_mangle]
        pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u32 {
            unsafe {
                let (program_id, mut accounts, data) = $crate::entrypoint::deserialize(input);
                $process_instruction(&program_id, &mut accounts, &data)
            }
        }
    };
}

/// Deserialize the input parameters
///
/// # Safety
#[allow(clippy::type_complexity)]
pub unsafe fn deserialize<'a>(input: *mut u8) -> (&'a Pubkey, Vec<AccountInfo<'a>>, &'a [u8]) {
    let mut offset: usize = 0;

    // Number of accounts present

    #[allow(clippy::cast_ptr_alignment)]
    let num_accounts = *(input.add(offset) as *const u64) as usize;
    offset += size_of::<u64>();

    // Account Infos

    let mut accounts = Vec::with_capacity(num_accounts);
    for _ in 0..num_accounts {
        let is_signer = {
            #[allow(clippy::cast_ptr_alignment)]
            let is_signer_val = *(input.add(offset) as *const u64);
            (is_signer_val != 0)
        };
        offset += size_of::<u64>();

        let key: &Pubkey = &*(input.add(offset) as *const Pubkey);
        offset += size_of::<Pubkey>();

        #[allow(clippy::cast_ptr_alignment)]
        let lamports = &mut *(input.add(offset) as *mut u64);
        offset += size_of::<u64>();

        #[allow(clippy::cast_ptr_alignment)]
        let data_length = *(input.add(offset) as *const u64) as usize;
        offset += size_of::<u64>();

        let data = { from_raw_parts_mut(input.add(offset), data_length) };
        offset += data_length;

        let owner: &Pubkey = &*(input.add(offset) as *const Pubkey);
        offset += size_of::<Pubkey>();

        accounts.push(AccountInfo {
            key,
            is_signer,
            lamports,
            data,
            owner,
        });
    }

    // Instruction data

    #[allow(clippy::cast_ptr_alignment)]
    let data_length = *(input.add(offset) as *const u64) as usize;
    offset += size_of::<u64>();

    let data = { from_raw_parts(input.add(offset), data_length) };
    offset += data_length;

    // Program Id

    let program_id: &Pubkey = &*(input.add(offset) as *const Pubkey);

    (program_id, accounts, data)
}