gemachain_program/
program.rs

1use crate::{
2    account_info::AccountInfo, entrypoint::ProgramResult, instruction::Instruction, pubkey::Pubkey,
3};
4
5/// Invoke a cross-program instruction
6///
7/// Note that the program id of the instruction being issued must also be included in
8/// `account_infos`.
9pub fn invoke(instruction: &Instruction, account_infos: &[AccountInfo]) -> ProgramResult {
10    invoke_signed(instruction, account_infos, &[])
11}
12
13/// Invoke a cross-program instruction with program signatures
14///
15/// Note that the program id of the instruction being issued must also be included in
16/// `account_infos`.
17pub fn invoke_signed(
18    instruction: &Instruction,
19    account_infos: &[AccountInfo],
20    signers_seeds: &[&[&[u8]]],
21) -> ProgramResult {
22    // Check that the account RefCells are consistent with the request
23    for account_meta in instruction.accounts.iter() {
24        for account_info in account_infos.iter() {
25            if account_meta.pubkey == *account_info.key {
26                if account_meta.is_writable {
27                    let _ = account_info.try_borrow_mut_carats()?;
28                    let _ = account_info.try_borrow_mut_data()?;
29                } else {
30                    let _ = account_info.try_borrow_carats()?;
31                    let _ = account_info.try_borrow_data()?;
32                }
33                break;
34            }
35        }
36    }
37
38    #[cfg(target_arch = "bpf")]
39    {
40        extern "C" {
41            fn gema_invoke_signed_rust(
42                instruction_addr: *const u8,
43                account_infos_addr: *const u8,
44                account_infos_len: u64,
45                signers_seeds_addr: *const u8,
46                signers_seeds_len: u64,
47            ) -> u64;
48        }
49
50        let result = unsafe {
51            gema_invoke_signed_rust(
52                instruction as *const _ as *const u8,
53                account_infos as *const _ as *const u8,
54                account_infos.len() as u64,
55                signers_seeds as *const _ as *const u8,
56                signers_seeds.len() as u64,
57            )
58        };
59        match result {
60            crate::entrypoint::SUCCESS => Ok(()),
61            _ => Err(result.into()),
62        }
63    }
64
65    #[cfg(not(target_arch = "bpf"))]
66    crate::program_stubs::gema_invoke_signed(instruction, account_infos, signers_seeds)
67}
68
69/// Maximum size that can be set using gema_set_return_data()
70pub const MAX_RETURN_DATA: usize = 1024;
71
72/// Set a program's return data
73pub fn set_return_data(data: &[u8]) {
74    #[cfg(target_arch = "bpf")]
75    {
76        extern "C" {
77            fn gema_set_return_data(data: *const u8, length: u64);
78        }
79
80        unsafe { gema_set_return_data(data.as_ptr(), data.len() as u64) };
81    }
82
83    #[cfg(not(target_arch = "bpf"))]
84    crate::program_stubs::gema_set_return_data(data)
85}
86
87/// Get the return data from invoked program
88pub fn get_return_data() -> Option<(Pubkey, Vec<u8>)> {
89    #[cfg(target_arch = "bpf")]
90    {
91        use std::cmp::min;
92
93        extern "C" {
94            fn gema_get_return_data(data: *mut u8, length: u64, program_id: *mut Pubkey) -> u64;
95        }
96
97        let mut buf = [0u8; MAX_RETURN_DATA];
98        let mut program_id = Pubkey::default();
99
100        let size =
101            unsafe { gema_get_return_data(buf.as_mut_ptr(), buf.len() as u64, &mut program_id) };
102
103        if size == 0 {
104            None
105        } else {
106            let size = min(size as usize, MAX_RETURN_DATA);
107            Some((program_id, buf[..size as usize].to_vec()))
108        }
109    }
110
111    #[cfg(not(target_arch = "bpf"))]
112    crate::program_stubs::gema_get_return_data()
113}