2022-02-02 16:45:57 -08:00
|
|
|
//! Example Rust-based BPF program that queries sibling instructions
|
|
|
|
|
|
|
|
#![cfg(feature = "program")]
|
|
|
|
|
|
|
|
use solana_program::{
|
|
|
|
account_info::AccountInfo,
|
|
|
|
entrypoint::ProgramResult,
|
|
|
|
instruction::{
|
|
|
|
get_processed_sibling_instruction, get_stack_height, AccountMeta, Instruction,
|
|
|
|
TRANSACTION_LEVEL_STACK_HEIGHT,
|
|
|
|
},
|
|
|
|
msg,
|
|
|
|
program::invoke,
|
|
|
|
pubkey::Pubkey,
|
|
|
|
};
|
|
|
|
|
2022-02-22 11:59:06 +08:00
|
|
|
solana_program::entrypoint!(process_instruction);
|
2022-02-02 16:45:57 -08:00
|
|
|
fn process_instruction(
|
|
|
|
_program_id: &Pubkey,
|
|
|
|
accounts: &[AccountInfo],
|
|
|
|
_instruction_data: &[u8],
|
|
|
|
) -> ProgramResult {
|
|
|
|
msg!("sibling");
|
|
|
|
|
|
|
|
// account 0 is mint
|
|
|
|
// account 1 is noop
|
|
|
|
// account 2 is invoke_and_return
|
|
|
|
// account 3 is sibling_inner
|
|
|
|
|
|
|
|
// Invoke child instructions
|
|
|
|
|
|
|
|
let instruction3 = Instruction::new_with_bytes(
|
|
|
|
*accounts[2].key,
|
|
|
|
&[3],
|
|
|
|
vec![AccountMeta::new_readonly(*accounts[1].key, false)],
|
|
|
|
);
|
|
|
|
let instruction2 = Instruction::new_with_bytes(
|
|
|
|
*accounts[1].key,
|
|
|
|
&[2],
|
|
|
|
vec![
|
|
|
|
AccountMeta::new_readonly(*accounts[0].key, true),
|
|
|
|
AccountMeta::new_readonly(*accounts[1].key, false),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
let instruction1 = Instruction::new_with_bytes(
|
|
|
|
*accounts[1].key,
|
|
|
|
&[1],
|
|
|
|
vec![
|
|
|
|
AccountMeta::new_readonly(*accounts[1].key, false),
|
|
|
|
AccountMeta::new_readonly(*accounts[0].key, true),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
let instruction0 = Instruction::new_with_bytes(
|
|
|
|
*accounts[3].key,
|
|
|
|
&[0],
|
|
|
|
vec![
|
|
|
|
AccountMeta::new_readonly(*accounts[0].key, false),
|
|
|
|
AccountMeta::new_readonly(*accounts[1].key, false),
|
|
|
|
AccountMeta::new_readonly(*accounts[2].key, false),
|
|
|
|
AccountMeta::new_readonly(*accounts[3].key, false),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
invoke(&instruction3, accounts)?;
|
|
|
|
invoke(&instruction2, accounts)?;
|
|
|
|
invoke(&instruction1, accounts)?;
|
|
|
|
invoke(&instruction0, accounts)?;
|
|
|
|
|
|
|
|
// Check sibling instructions
|
|
|
|
|
|
|
|
let sibling_instruction1 = Instruction::new_with_bytes(
|
|
|
|
*accounts[1].key,
|
|
|
|
&[43],
|
|
|
|
vec![
|
|
|
|
AccountMeta::new_readonly(*accounts[1].key, false),
|
|
|
|
AccountMeta::new(*accounts[0].key, true),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
let sibling_instruction0 = Instruction::new_with_bytes(
|
|
|
|
*accounts[1].key,
|
|
|
|
&[42],
|
|
|
|
vec![
|
|
|
|
AccountMeta::new(*accounts[0].key, true),
|
|
|
|
AccountMeta::new_readonly(*accounts[1].key, false),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(TRANSACTION_LEVEL_STACK_HEIGHT, get_stack_height());
|
|
|
|
assert_eq!(
|
|
|
|
get_processed_sibling_instruction(0),
|
|
|
|
Some(sibling_instruction0)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
get_processed_sibling_instruction(1),
|
|
|
|
Some(sibling_instruction1)
|
|
|
|
);
|
|
|
|
assert_eq!(get_processed_sibling_instruction(2), None);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|