Add get_processed_sibling_instruction syscall (#22859) (#22956)

This commit is contained in:
Jack May
2022-02-08 09:21:11 -08:00
committed by GitHub
parent 5c69af607d
commit d05b5b0902
19 changed files with 864 additions and 66 deletions

View File

@ -528,7 +528,8 @@ pub fn checked_add(a: u64, b: u64) -> Result<u64, InstructionError> {
/// default [`AccountMeta::new`] constructor creates writable accounts, this is
/// a minor hazard: use [`AccountMeta::new_readonly`] to specify that an account
/// is not writable.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[repr(C)]
#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize)]
pub struct AccountMeta {
/// An account's public key.
pub pubkey: Pubkey,
@ -639,8 +640,16 @@ impl CompiledInstruction {
let data = serialize(data).unwrap();
Self {
program_id_index: program_ids_index,
data,
accounts,
data,
}
}
pub fn new_from_raw_parts(program_id_index: u8, data: Vec<u8>, accounts: Vec<u8>) -> Self {
Self {
program_id_index,
accounts,
data,
}
}
@ -667,6 +676,32 @@ impl CompiledInstruction {
}
Ok(())
}
#[cfg(not(target_arch = "bpf"))]
pub fn decompile(
&self,
message: &crate::message::SanitizedMessage,
) -> Result<Instruction, InstructionError> {
Ok(Instruction::new_with_bytes(
*message
.get_account_key(self.program_id_index as usize)
.ok_or(InstructionError::MissingAccount)?,
&self.data,
self.accounts
.iter()
.map(|account_index| {
let account_index = *account_index as usize;
Ok(AccountMeta {
is_signer: message.is_signer(account_index),
is_writable: message.is_writable(account_index),
pubkey: *message
.get_account_key(account_index)
.ok_or(InstructionError::MissingAccount)?,
})
})
.collect::<Result<Vec<AccountMeta>, InstructionError>>()?,
))
}
}
#[cfg(test)]
@ -696,3 +731,137 @@ mod test {
assert_eq!((0, 2), do_work(&[2, 2]));
}
}
/// Use to query and convey information about the sibling instruction components
/// when calling the `sol_get_processed_sibling_instruction` syscall.
#[repr(C)]
#[derive(Default, Debug, Clone, Copy)]
pub struct ProcessedSiblingInstruction {
/// Length of the instruction data
pub data_len: usize,
/// Number of AccountMeta structures
pub accounts_len: usize,
}
/// Returns a sibling instruction from the processed sibling instruction list.
///
/// The processed sibling instruction list is a reverse-ordered list of
/// successfully processed sibling instructions. For example, given the call flow:
///
/// A
/// B -> C -> D
/// B -> E
/// B -> F
///
/// Then B's processed sibling instruction list is: `[A]`
/// Then F's processed sibling instruction list is: `[E, C]`
pub fn get_processed_sibling_instruction(index: usize) -> Option<Instruction> {
#[cfg(target_arch = "bpf")]
{
extern "C" {
fn sol_get_processed_sibling_instruction(
index: u64,
meta: *mut ProcessedSiblingInstruction,
program_id: *mut Pubkey,
data: *mut u8,
accounts: *mut AccountMeta,
) -> u64;
}
let mut meta = ProcessedSiblingInstruction::default();
let mut program_id = Pubkey::default();
if 1 == unsafe {
sol_get_processed_sibling_instruction(
index as u64,
&mut meta,
&mut program_id,
&mut u8::default(),
&mut AccountMeta::default(),
)
} {
let mut data = Vec::new();
let mut accounts = Vec::new();
data.resize_with(meta.data_len, u8::default);
accounts.resize_with(meta.accounts_len, AccountMeta::default);
let _ = unsafe {
sol_get_processed_sibling_instruction(
index as u64,
&mut meta,
&mut program_id,
data.as_mut_ptr(),
accounts.as_mut_ptr(),
)
};
Some(Instruction::new_with_bytes(program_id, &data, accounts))
} else {
None
}
}
#[cfg(not(target_arch = "bpf"))]
crate::program_stubs::sol_get_processed_sibling_instruction(index)
}
// Stack height when processing transaction-level instructions
pub const TRANSACTION_LEVEL_STACK_HEIGHT: usize = 1;
/// Get the current stack height, transaction-level instructions are height
/// TRANSACTION_LEVEL_STACK_HEIGHT, fist invoked inner instruction is height
/// TRANSACTION_LEVEL_STACK_HEIGHT + 1, etc...
pub fn get_stack_height() -> usize {
#[cfg(target_arch = "bpf")]
{
extern "C" {
fn sol_get_stack_height() -> u64;
}
unsafe { sol_get_stack_height() as usize }
}
#[cfg(not(target_arch = "bpf"))]
{
crate::program_stubs::sol_get_stack_height() as usize
}
}
#[test]
fn test_account_meta_layout() {
#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize)]
struct AccountMetaRust {
pub pubkey: Pubkey,
pub is_signer: bool,
pub is_writable: bool,
}
let account_meta_rust = AccountMetaRust::default();
let base_rust_addr = &account_meta_rust as *const _ as u64;
let pubkey_rust_addr = &account_meta_rust.pubkey as *const _ as u64;
let is_signer_rust_addr = &account_meta_rust.is_signer as *const _ as u64;
let is_writable_rust_addr = &account_meta_rust.is_writable as *const _ as u64;
let account_meta_c = AccountMeta::default();
let base_c_addr = &account_meta_c as *const _ as u64;
let pubkey_c_addr = &account_meta_c.pubkey as *const _ as u64;
let is_signer_c_addr = &account_meta_c.is_signer as *const _ as u64;
let is_writable_c_addr = &account_meta_c.is_writable as *const _ as u64;
assert_eq!(
std::mem::size_of::<AccountMetaRust>(),
std::mem::size_of::<AccountMeta>()
);
assert_eq!(
pubkey_rust_addr - base_rust_addr,
pubkey_c_addr - base_c_addr
);
assert_eq!(
is_signer_rust_addr - base_rust_addr,
is_signer_c_addr - base_c_addr
);
assert_eq!(
is_writable_rust_addr - base_rust_addr,
is_writable_c_addr - base_c_addr
);
}

View File

@ -91,6 +91,12 @@ pub trait SyscallStubs: Sync + Send {
fn sol_log_data(&self, fields: &[&[u8]]) {
println!("data: {}", fields.iter().map(base64::encode).join(" "));
}
fn sol_get_processed_sibling_instruction(&self, _index: usize) -> Option<Instruction> {
None
}
fn sol_get_stack_height(&self) -> u64 {
0
}
}
struct DefaultSyscallStubs {}
@ -176,3 +182,14 @@ pub(crate) fn sol_set_return_data(data: &[u8]) {
pub(crate) fn sol_log_data(data: &[&[u8]]) {
SYSCALL_STUBS.read().unwrap().sol_log_data(data)
}
pub(crate) fn sol_get_processed_sibling_instruction(index: usize) -> Option<Instruction> {
SYSCALL_STUBS
.read()
.unwrap()
.sol_get_processed_sibling_instruction(index)
}
pub(crate) fn sol_get_stack_height() -> u64 {
SYSCALL_STUBS.read().unwrap().sol_get_stack_height()
}