Skip to content

Commit

Permalink
Move SBF internals to own mod
Browse files Browse the repository at this point in the history
  • Loading branch information
riptl committed Jul 13, 2022
1 parent 6b0f9b3 commit 807eca2
Showing 1 changed file with 133 additions and 132 deletions.
265 changes: 133 additions & 132 deletions programs/bpf_loader/src/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2027,154 +2027,154 @@ struct CallerAccount<'a> {
}
type TranslatedAccounts<'a> = Vec<(usize, Option<CallerAccount<'a>>)>;

/// Stable representation of a `Vec<T>` in the SBFv2 Rust runtime.
/// Only supports the global allocator.
// Size: 0x18 (24 bytes)
#[repr(C)]
struct RustVMVec<T: Sized> {
ptr: u64, // 0x00 (8 bytes)
raw_cap: u64, // 0x08 (8 bytes)
raw_len: u64, // 0x10 (8 bytes)
_phantom: PhantomData<T>,
}

impl<T: Sized> RustVMVec<T> {
fn len(&self) -> usize {
// An u64 to usize conversion can only fail in the case of an overflow.
// Realistically, this only happens on 32-bit architectures.
// Assuming available memory in a VM will never exceed 4 GiB,
// "saturating" to UINT32_MAX safely reaches the "slice too large" error path
// that a comparable larger value would also trigger on a 64-bit architecture.
self.raw_len.try_into().unwrap_or(usize::MAX)
mod sbf_internal {
use super::*;

/// Stable representation of a `Vec<T>` in the SBFv2 Rust runtime.
/// Only supports the global allocator.
// Size: 0x18 (24 bytes)
#[repr(C)]
pub(crate) struct StdVec<T: Sized> {
pub(crate) ptr: u64, // 0x00 (8 bytes)
pub(crate) raw_cap: u64, // 0x08 (8 bytes)
pub(crate) raw_len: u64, // 0x10 (8 bytes)
_phantom: PhantomData<T>,
}

/// Returns a slice to the elements pointed to by the Vec object.
fn translate(
&self,
memory_mapping: &MemoryMapping,
invoke_context: &InvokeContext,
) -> Result<&[T], EbpfError<BpfError>> {
translate_slice(
memory_mapping,
self.ptr,
self.raw_len,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)
impl<T: Sized> StdVec<T> {
pub(crate) fn len(&self) -> usize {
// An u64 to usize conversion can only fail in the case of an overflow.
// Realistically, this only happens on 32-bit architectures.
// Assuming available memory in a VM will never exceed 4 GiB,
// "saturating" to UINT32_MAX safely reaches the "slice too large" error path
// that a comparable larger value would also trigger on a 64-bit architecture.
self.raw_len.try_into().unwrap_or(usize::MAX)
}

/// Returns a slice to the elements pointed to by the Vec object.
pub(crate) fn translate(
&self,
memory_mapping: &MemoryMapping,
invoke_context: &InvokeContext,
) -> Result<&[T], EbpfError<BpfError>> {
translate_slice(
memory_mapping,
self.ptr,
self.raw_len,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)
}
}
}

/// Stable representation of a `solana_program::instruction::Instruction`
/// in the SBFv2 Rust runtime.
// Size: 0x50 (80 bytes)
#[repr(C)]
struct RustVMInstruction {
accounts: RustVMVec<AccountMeta>, // 0x00 (24 bytes)
data: RustVMVec<u8>, // 0x18 (24 bytes)
program_id: Pubkey, // 0x30 (32 bytes)
}
/// Stable representation of a `solana_program::instruction::Instruction`
/// in the SBFv2 Rust runtime.
// Size: 0x50 (80 bytes)
#[repr(C)]
pub(crate) struct Instruction {
pub(crate) accounts: StdVec<AccountMeta>, // 0x00 (24 bytes)
pub(crate) data: StdVec<u8>, // 0x18 (24 bytes)
pub(crate) program_id: Pubkey, // 0x30 (32 bytes)
}

impl RustVMInstruction {
/// Returns a reference to an Instruction object at the given VM memory address.
fn from_vm_memory<'a>(
memory_mapping: &MemoryMapping<'a>,
vm_addr: u64,
invoke_context: &InvokeContext<'_>,
) -> Result<&'a Self, EbpfError<BpfError>> {
translate_type(memory_mapping, vm_addr, invoke_context.get_check_aligned())
#[repr(C)]
pub(crate) struct Ptr<T: Sized> {
pub(crate) ptr: u64,
_phantom: PhantomData<T>,
}
}

#[repr(C)]
struct RustVMPtr<T: Sized> {
ptr: u64,
_phantom: PhantomData<T>,
}
impl<T: Sized> Ptr<T> {
pub(crate) fn new(vm_addr: u64) -> Self {
Self {
ptr: vm_addr,
_phantom: PhantomData::default(),
}
}

impl<T: Sized> RustVMPtr<T> {
fn translate<'a>(
&self,
memory_mapping: &MemoryMapping,
invoke_context: &InvokeContext,
) -> Result<&'a T, EbpfError<BpfError>> {
translate_type(memory_mapping, self.ptr, invoke_context.get_check_aligned())
pub(crate) fn translate<'a>(
&self,
memory_mapping: &MemoryMapping,
invoke_context: &InvokeContext,
) -> Result<&'a T, EbpfError<BpfError>> {
translate_type(memory_mapping, self.ptr, invoke_context.get_check_aligned())
}

pub(crate) fn translate_mut<'a>(
&self,
memory_mapping: &MemoryMapping,
invoke_context: &InvokeContext,
) -> Result<&'a mut T, EbpfError<BpfError>> {
translate_type_mut(memory_mapping, self.ptr, invoke_context.get_check_aligned())
}
}

fn translate_mut<'a>(
&self,
memory_mapping: &MemoryMapping,
invoke_context: &InvokeContext,
) -> Result<&'a mut T, EbpfError<BpfError>> {
translate_type_mut(memory_mapping, self.ptr, invoke_context.get_check_aligned())
#[repr(C)]
pub(crate) struct StdRcBox<T: Sized> {
_strong: u64,
_weak: u64,
pub(crate) value: T,
}
}

#[repr(C)]
struct RustVMRcBox<T: Sized> {
strong: u64,
weak: u64,
value: T,
}
#[repr(C)]
pub(crate) struct StdRefCell<T: Sized> {
_borrow: i64,
pub(crate) value: T,
}

#[repr(C)]
struct RustVMRefCell<T: Sized> {
borrow: i64,
value: T,
}
#[repr(C)]
pub(crate) struct Slice<T: Sized> {
pub(crate) ptr: u64,
pub(crate) len: u64,
_phantom: PhantomData<T>,
}

#[repr(C)]
struct RustVMSlice<T: Sized> {
ptr: u64,
len: u64,
_phantom: PhantomData<T>,
}
impl<T: Sized> Slice<T> {
pub(crate) fn translate<'a>(
&self,
memory_mapping: &MemoryMapping,
invoke_context: &InvokeContext,
) -> Result<&'a [T], EbpfError<BpfError>> {
translate_slice(
memory_mapping,
self.ptr,
self.len,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)
}

impl<T: Sized> RustVMSlice<T> {
fn translate<'a>(
&self,
memory_mapping: &MemoryMapping,
invoke_context: &InvokeContext,
) -> Result<&'a [T], EbpfError<BpfError>> {
translate_slice(
memory_mapping,
self.ptr,
self.len,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)
pub(crate) fn translate_mut<'a>(
&self,
memory_mapping: &MemoryMapping,
invoke_context: &InvokeContext,
) -> Result<&'a mut [T], EbpfError<BpfError>> {
translate_slice_mut(
memory_mapping,
self.ptr,
self.len,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)
}
}

fn translate_mut<'a>(
&self,
memory_mapping: &MemoryMapping,
invoke_context: &InvokeContext,
) -> Result<&'a mut [T], EbpfError<BpfError>> {
translate_slice_mut(
memory_mapping,
self.ptr,
self.len,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)
/// Stable instruction of a `solana_program::account_info::AccountInfo`
/// in the SBFv2 Rust runtime.
// Size: 0x30 (48 bytes)
#[repr(C)]
pub(crate) struct AccountInfo {
pub(crate) key: Ptr<Pubkey>, // 0x00 (8 bytes)
pub(crate) lamports: Ptr<StdRcBox<StdRefCell<Ptr<u64>>>>, // 0x08 (8 bytes)
pub(crate) data: Ptr<StdRcBox<StdRefCell<Slice<u8>>>>, // 0x10 (8 bytes)
pub(crate) owner: Ptr<Pubkey>, // 0x18 (8 bytes)
pub(crate) rent_epoch: u64, // 0x20 (8 bytes)
pub(crate) is_signer: bool, // 0x28 (1 byte)
pub(crate) is_writable: bool, // 0x29 (1 byte)
pub(crate) executable: bool, // 0x2a (1 byte)
_padding: [u8; 5], // 0x30 (5 bytes)
}
}

/// Stable instruction of a `solana_program::account_info::AccountInfo`
/// in the SBFv2 Rust runtime.
// Size: 0x30 (48 bytes)
#[repr(C)]
struct RustVMAccountInfo {
key: RustVMPtr<Pubkey>, // 0x00 (8 bytes)
lamports: RustVMPtr<RustVMRcBox<RustVMRefCell<RustVMPtr<u64>>>>, // 0x08 (8 bytes)
data: RustVMPtr<RustVMRcBox<RustVMRefCell<RustVMSlice<u8>>>>, // 0x10 (8 bytes)
owner: RustVMPtr<Pubkey>, // 0x18 (8 bytes)
rent_epoch: u64, // 0x20 (8 bytes)
is_signer: bool, // 0x28 (1 byte)
is_writable: bool, // 0x29 (1 byte)
executable: bool, // 0x2a (1 byte)
_padding: [u8; 5], // 0x30 (5 bytes)
}

/// Implemented by language specific data structure translators
trait SyscallInvokeSigned<'a, 'b> {
fn get_context_mut(&self) -> Result<RefMut<&'a mut InvokeContext<'b>>, EbpfError<BpfError>>;
Expand Down Expand Up @@ -2241,7 +2241,8 @@ impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedRust<'a, 'b> {
memory_mapping: &mut MemoryMapping,
invoke_context: &mut InvokeContext,
) -> Result<Instruction, EbpfError<BpfError>> {
let ix = RustVMInstruction::from_vm_memory(memory_mapping, addr, invoke_context)?;
let ix: &sbf_internal::Instruction =
sbf_internal::Ptr::new(addr).translate(memory_mapping, invoke_context)?;

check_instruction_size(ix.accounts.len(), ix.data.len(), invoke_context)?;

Expand All @@ -2266,7 +2267,7 @@ impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedRust<'a, 'b> {
memory_mapping: &mut MemoryMapping,
invoke_context: &mut InvokeContext,
) -> Result<TranslatedAccounts<'c>, EbpfError<BpfError>> {
let account_infos = translate_slice::<RustVMAccountInfo>(
let account_infos = translate_slice::<sbf_internal::AccountInfo>(
memory_mapping,
account_infos_addr,
account_infos_len,
Expand All @@ -2279,7 +2280,7 @@ impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedRust<'a, 'b> {
.map(|account_info| account_info.key.translate(memory_mapping, invoke_context))
.collect::<Result<Vec<_>, EbpfError<BpfError>>>()?;

let translate = |account_info: &RustVMAccountInfo, invoke_context: &InvokeContext| {
let translate = |account_info: &sbf_internal::AccountInfo, invoke_context: &InvokeContext| {
// Translate the account from user space

let lamports = account_info
Expand Down Expand Up @@ -2357,7 +2358,7 @@ impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedRust<'a, 'b> {
) -> Result<Vec<Pubkey>, EbpfError<BpfError>> {
let mut signers = Vec::new();
if signers_seeds_len > 0 {
let signers_seeds = translate_slice::<RustVMSlice<RustVMSlice<u8>>>(
let signers_seeds = translate_slice::<sbf_internal::Slice<sbf_internal::Slice<u8>>>(
memory_mapping,
signers_seeds_addr,
signers_seeds_len,
Expand Down

0 comments on commit 807eca2

Please sign in to comment.