|
| 1 | +//! Rust example using pinocchio demonstrating invoking another program |
| 2 | +#![deny(missing_docs)] |
| 3 | + |
| 4 | +use pinocchio::{ |
| 5 | + instruction::{Account, AccountMeta, Instruction}, |
| 6 | + lazy_entrypoint::InstructionContext, |
| 7 | + program::invoke_signed_unchecked, |
| 8 | + program_error::ProgramError, |
| 9 | + pubkey::create_program_address, |
| 10 | + signer, ProgramResult, |
| 11 | +}; |
| 12 | + |
| 13 | +// Since this is a single instruction program, we use the "lazy" variation |
| 14 | +// of the entrypoint. |
| 15 | +pinocchio::lazy_entrypoint!(process_instruction); |
| 16 | + |
| 17 | +/// Amount of bytes of account data to allocate |
| 18 | +pub const SIZE: usize = 42; |
| 19 | + |
| 20 | +/// Instruction processor. |
| 21 | +fn process_instruction(mut context: InstructionContext) -> ProgramResult { |
| 22 | + if context.remaining() != 2 { |
| 23 | + return Err(ProgramError::NotEnoughAccountKeys); |
| 24 | + } |
| 25 | + |
| 26 | + // Account info to allocate and for the program being invoked. We know that |
| 27 | + // we got 2 accounts, so it is ok use `next_account_unchecked` twice. |
| 28 | + let allocated_info = unsafe { context.next_account_unchecked().assume_account() }; |
| 29 | + // just move the offset, we don't need the system program info |
| 30 | + let _system_program_info = unsafe { context.next_account_unchecked() }; |
| 31 | + |
| 32 | + // Again, don't need to check that all accounts have been consumed, we know |
| 33 | + // we have exactly 2 accounts. |
| 34 | + let (instruction_data, program_id) = unsafe { context.instruction_data_unchecked() }; |
| 35 | + |
| 36 | + let expected_allocated_key = |
| 37 | + create_program_address(&[b"You pass butter", &[instruction_data[0]]], program_id)?; |
| 38 | + if *allocated_info.key() != expected_allocated_key { |
| 39 | + // allocated key does not match the derived address |
| 40 | + return Err(ProgramError::InvalidArgument); |
| 41 | + } |
| 42 | + |
| 43 | + // Invoke the system program to allocate account data |
| 44 | + let mut data = [0; 12]; |
| 45 | + data[0] = 8; // ix discriminator |
| 46 | + data[4..12].copy_from_slice(&SIZE.to_le_bytes()); |
| 47 | + |
| 48 | + let instruction = Instruction { |
| 49 | + program_id: &pinocchio_system::ID, |
| 50 | + accounts: &[AccountMeta::writable_signer(allocated_info.key())], |
| 51 | + data: &data, |
| 52 | + }; |
| 53 | + |
| 54 | + // Invoke the system program with the 'unchecked' function - this is ok since |
| 55 | + // we know the accounts are not borrowed elsewhere. |
| 56 | + unsafe { |
| 57 | + invoke_signed_unchecked( |
| 58 | + &instruction, |
| 59 | + &[Account::from(&allocated_info)], |
| 60 | + &[signer!(b"You pass butter", &[instruction_data[0]])], |
| 61 | + ) |
| 62 | + }; |
| 63 | + |
| 64 | + Ok(()) |
| 65 | +} |
0 commit comments