Refactor: split up syscalls module (#26637)
* Refactor: split up syscalls module * fix ci script * fix visibility
This commit is contained in:
parent
9714cb3764
commit
07d7c938b9
|
@ -14,7 +14,7 @@ use {
|
|||
* to verify undefined symbols in a .so module that cargo-build-bpf has built.
|
||||
*/
|
||||
fn main() {
|
||||
let syscalls_rs_path = PathBuf::from("../src/syscalls.rs");
|
||||
let syscalls_rs_path = PathBuf::from("../src/syscalls/mod.rs");
|
||||
let syscalls_txt_path = PathBuf::from("../../../sdk/bpf/syscalls.txt");
|
||||
println!(
|
||||
"cargo:warning=(not a warning) Generating {1} from {0}",
|
||||
|
|
|
@ -0,0 +1,927 @@
|
|||
use {super::*, crate::declare_syscall};
|
||||
|
||||
struct CallerAccount<'a> {
|
||||
lamports: &'a mut u64,
|
||||
owner: &'a mut Pubkey,
|
||||
original_data_len: usize,
|
||||
data: &'a mut [u8],
|
||||
vm_data_addr: u64,
|
||||
ref_to_len_in_vm: &'a mut u64,
|
||||
serialized_len_ptr: &'a mut u64,
|
||||
executable: bool,
|
||||
rent_epoch: u64,
|
||||
}
|
||||
type TranslatedAccounts<'a> = Vec<(usize, Option<CallerAccount<'a>>)>;
|
||||
|
||||
/// Implemented by language specific data structure translators
|
||||
trait SyscallInvokeSigned<'a, 'b> {
|
||||
fn get_context_mut(&self) -> Result<RefMut<&'a mut InvokeContext<'b>>, EbpfError<BpfError>>;
|
||||
fn translate_instruction(
|
||||
&self,
|
||||
addr: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
invoke_context: &mut InvokeContext,
|
||||
) -> Result<Instruction, EbpfError<BpfError>>;
|
||||
fn translate_accounts<'c>(
|
||||
&'c self,
|
||||
instruction_accounts: &[InstructionAccount],
|
||||
program_indices: &[usize],
|
||||
account_infos_addr: u64,
|
||||
account_infos_len: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
invoke_context: &mut InvokeContext,
|
||||
) -> Result<TranslatedAccounts<'c>, EbpfError<BpfError>>;
|
||||
fn translate_signers(
|
||||
&self,
|
||||
program_id: &Pubkey,
|
||||
signers_seeds_addr: u64,
|
||||
signers_seeds_len: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
invoke_context: &InvokeContext,
|
||||
) -> Result<Vec<Pubkey>, EbpfError<BpfError>>;
|
||||
}
|
||||
|
||||
declare_syscall!(
|
||||
/// Cross-program invocation called from Rust
|
||||
SyscallInvokeSignedRust,
|
||||
fn call(
|
||||
&mut self,
|
||||
instruction_addr: u64,
|
||||
account_infos_addr: u64,
|
||||
account_infos_len: u64,
|
||||
signers_seeds_addr: u64,
|
||||
signers_seeds_len: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
result: &mut Result<u64, EbpfError<BpfError>>,
|
||||
) {
|
||||
*result = call(
|
||||
self,
|
||||
instruction_addr,
|
||||
account_infos_addr,
|
||||
account_infos_len,
|
||||
signers_seeds_addr,
|
||||
signers_seeds_len,
|
||||
memory_mapping,
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedRust<'a, 'b> {
|
||||
fn get_context_mut(&self) -> Result<RefMut<&'a mut InvokeContext<'b>>, EbpfError<BpfError>> {
|
||||
self.invoke_context
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed.into())
|
||||
}
|
||||
|
||||
fn translate_instruction(
|
||||
&self,
|
||||
addr: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
invoke_context: &mut InvokeContext,
|
||||
) -> Result<Instruction, EbpfError<BpfError>> {
|
||||
let ix = translate_type::<Instruction>(
|
||||
memory_mapping,
|
||||
addr,
|
||||
invoke_context.get_check_aligned(),
|
||||
)?;
|
||||
|
||||
check_instruction_size(ix.accounts.len(), ix.data.len(), invoke_context)?;
|
||||
|
||||
let accounts = translate_slice::<AccountMeta>(
|
||||
memory_mapping,
|
||||
ix.accounts.as_ptr() as u64,
|
||||
ix.accounts.len() as u64,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size(),
|
||||
)?
|
||||
.to_vec();
|
||||
let data = translate_slice::<u8>(
|
||||
memory_mapping,
|
||||
ix.data.as_ptr() as u64,
|
||||
ix.data.len() as u64,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size(),
|
||||
)?
|
||||
.to_vec();
|
||||
Ok(Instruction {
|
||||
program_id: ix.program_id,
|
||||
accounts,
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
fn translate_accounts<'c>(
|
||||
&'c self,
|
||||
instruction_accounts: &[InstructionAccount],
|
||||
program_indices: &[usize],
|
||||
account_infos_addr: u64,
|
||||
account_infos_len: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
invoke_context: &mut InvokeContext,
|
||||
) -> Result<TranslatedAccounts<'c>, EbpfError<BpfError>> {
|
||||
let account_infos = translate_slice::<AccountInfo>(
|
||||
memory_mapping,
|
||||
account_infos_addr,
|
||||
account_infos_len,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size(),
|
||||
)?;
|
||||
check_account_infos(account_infos.len(), invoke_context)?;
|
||||
let account_info_keys = account_infos
|
||||
.iter()
|
||||
.map(|account_info| {
|
||||
translate_type::<Pubkey>(
|
||||
memory_mapping,
|
||||
account_info.key as *const _ as u64,
|
||||
invoke_context.get_check_aligned(),
|
||||
)
|
||||
})
|
||||
.collect::<Result<Vec<_>, EbpfError<BpfError>>>()?;
|
||||
|
||||
let translate = |account_info: &AccountInfo, invoke_context: &InvokeContext| {
|
||||
// Translate the account from user space
|
||||
|
||||
let lamports = {
|
||||
// Double translate lamports out of RefCell
|
||||
let ptr = translate_type::<u64>(
|
||||
memory_mapping,
|
||||
account_info.lamports.as_ptr() as u64,
|
||||
invoke_context.get_check_aligned(),
|
||||
)?;
|
||||
translate_type_mut::<u64>(memory_mapping, *ptr, invoke_context.get_check_aligned())?
|
||||
};
|
||||
let owner = translate_type_mut::<Pubkey>(
|
||||
memory_mapping,
|
||||
account_info.owner as *const _ as u64,
|
||||
invoke_context.get_check_aligned(),
|
||||
)?;
|
||||
|
||||
let (data, vm_data_addr, ref_to_len_in_vm, serialized_len_ptr) = {
|
||||
// Double translate data out of RefCell
|
||||
let data = *translate_type::<&[u8]>(
|
||||
memory_mapping,
|
||||
account_info.data.as_ptr() as *const _ as u64,
|
||||
invoke_context.get_check_aligned(),
|
||||
)?;
|
||||
|
||||
invoke_context.get_compute_meter().consume(
|
||||
(data.len() as u64)
|
||||
.saturating_div(invoke_context.get_compute_budget().cpi_bytes_per_unit),
|
||||
)?;
|
||||
|
||||
let translated = translate(
|
||||
memory_mapping,
|
||||
AccessType::Store,
|
||||
(account_info.data.as_ptr() as *const u64 as u64)
|
||||
.saturating_add(size_of::<u64>() as u64),
|
||||
8,
|
||||
)? as *mut u64;
|
||||
let ref_to_len_in_vm = unsafe { &mut *translated };
|
||||
let ref_of_len_in_input_buffer =
|
||||
(data.as_ptr() as *const _ as u64).saturating_sub(8);
|
||||
let serialized_len_ptr = translate_type_mut::<u64>(
|
||||
memory_mapping,
|
||||
ref_of_len_in_input_buffer,
|
||||
invoke_context.get_check_aligned(),
|
||||
)?;
|
||||
let vm_data_addr = data.as_ptr() as u64;
|
||||
(
|
||||
translate_slice_mut::<u8>(
|
||||
memory_mapping,
|
||||
vm_data_addr,
|
||||
data.len() as u64,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size(),
|
||||
)?,
|
||||
vm_data_addr,
|
||||
ref_to_len_in_vm,
|
||||
serialized_len_ptr,
|
||||
)
|
||||
};
|
||||
|
||||
Ok(CallerAccount {
|
||||
lamports,
|
||||
owner,
|
||||
original_data_len: 0, // set later
|
||||
data,
|
||||
vm_data_addr,
|
||||
ref_to_len_in_vm,
|
||||
serialized_len_ptr,
|
||||
executable: account_info.executable,
|
||||
rent_epoch: account_info.rent_epoch,
|
||||
})
|
||||
};
|
||||
|
||||
get_translated_accounts(
|
||||
instruction_accounts,
|
||||
program_indices,
|
||||
&account_info_keys,
|
||||
account_infos,
|
||||
invoke_context,
|
||||
translate,
|
||||
)
|
||||
}
|
||||
|
||||
fn translate_signers(
|
||||
&self,
|
||||
program_id: &Pubkey,
|
||||
signers_seeds_addr: u64,
|
||||
signers_seeds_len: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
invoke_context: &InvokeContext,
|
||||
) -> Result<Vec<Pubkey>, EbpfError<BpfError>> {
|
||||
let mut signers = Vec::new();
|
||||
if signers_seeds_len > 0 {
|
||||
let signers_seeds = translate_slice::<&[&[u8]]>(
|
||||
memory_mapping,
|
||||
signers_seeds_addr,
|
||||
signers_seeds_len,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size(),
|
||||
)?;
|
||||
if signers_seeds.len() > MAX_SIGNERS {
|
||||
return Err(SyscallError::TooManySigners.into());
|
||||
}
|
||||
for signer_seeds in signers_seeds.iter() {
|
||||
let untranslated_seeds = translate_slice::<&[u8]>(
|
||||
memory_mapping,
|
||||
signer_seeds.as_ptr() as *const _ as u64,
|
||||
signer_seeds.len() as u64,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size(),
|
||||
)?;
|
||||
if untranslated_seeds.len() > MAX_SEEDS {
|
||||
return Err(SyscallError::InstructionError(
|
||||
InstructionError::MaxSeedLengthExceeded,
|
||||
)
|
||||
.into());
|
||||
}
|
||||
let seeds = untranslated_seeds
|
||||
.iter()
|
||||
.map(|untranslated_seed| {
|
||||
translate_slice::<u8>(
|
||||
memory_mapping,
|
||||
untranslated_seed.as_ptr() as *const _ as u64,
|
||||
untranslated_seed.len() as u64,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size(),
|
||||
)
|
||||
})
|
||||
.collect::<Result<Vec<_>, EbpfError<BpfError>>>()?;
|
||||
let signer = Pubkey::create_program_address(&seeds, program_id)
|
||||
.map_err(SyscallError::BadSeeds)?;
|
||||
signers.push(signer);
|
||||
}
|
||||
Ok(signers)
|
||||
} else {
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Rust representation of C's SolInstruction
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
struct SolInstruction {
|
||||
program_id_addr: u64,
|
||||
accounts_addr: u64,
|
||||
accounts_len: u64,
|
||||
data_addr: u64,
|
||||
data_len: u64,
|
||||
}
|
||||
|
||||
/// Rust representation of C's SolAccountMeta
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
struct SolAccountMeta {
|
||||
pubkey_addr: u64,
|
||||
is_writable: bool,
|
||||
is_signer: bool,
|
||||
}
|
||||
|
||||
/// Rust representation of C's SolAccountInfo
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
struct SolAccountInfo {
|
||||
key_addr: u64,
|
||||
lamports_addr: u64,
|
||||
data_len: u64,
|
||||
data_addr: u64,
|
||||
owner_addr: u64,
|
||||
rent_epoch: u64,
|
||||
#[allow(dead_code)]
|
||||
is_signer: bool,
|
||||
#[allow(dead_code)]
|
||||
is_writable: bool,
|
||||
executable: bool,
|
||||
}
|
||||
|
||||
/// Rust representation of C's SolSignerSeed
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
struct SolSignerSeedC {
|
||||
addr: u64,
|
||||
len: u64,
|
||||
}
|
||||
|
||||
/// Rust representation of C's SolSignerSeeds
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
struct SolSignerSeedsC {
|
||||
addr: u64,
|
||||
len: u64,
|
||||
}
|
||||
|
||||
declare_syscall!(
|
||||
/// Cross-program invocation called from C
|
||||
SyscallInvokeSignedC,
|
||||
fn call(
|
||||
&mut self,
|
||||
instruction_addr: u64,
|
||||
account_infos_addr: u64,
|
||||
account_infos_len: u64,
|
||||
signers_seeds_addr: u64,
|
||||
signers_seeds_len: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
result: &mut Result<u64, EbpfError<BpfError>>,
|
||||
) {
|
||||
*result = call(
|
||||
self,
|
||||
instruction_addr,
|
||||
account_infos_addr,
|
||||
account_infos_len,
|
||||
signers_seeds_addr,
|
||||
signers_seeds_len,
|
||||
memory_mapping,
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedC<'a, 'b> {
|
||||
fn get_context_mut(&self) -> Result<RefMut<&'a mut InvokeContext<'b>>, EbpfError<BpfError>> {
|
||||
self.invoke_context
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed.into())
|
||||
}
|
||||
|
||||
fn translate_instruction(
|
||||
&self,
|
||||
addr: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
invoke_context: &mut InvokeContext,
|
||||
) -> Result<Instruction, EbpfError<BpfError>> {
|
||||
let ix_c = translate_type::<SolInstruction>(
|
||||
memory_mapping,
|
||||
addr,
|
||||
invoke_context.get_check_aligned(),
|
||||
)?;
|
||||
|
||||
check_instruction_size(
|
||||
ix_c.accounts_len as usize,
|
||||
ix_c.data_len as usize,
|
||||
invoke_context,
|
||||
)?;
|
||||
let program_id = translate_type::<Pubkey>(
|
||||
memory_mapping,
|
||||
ix_c.program_id_addr,
|
||||
invoke_context.get_check_aligned(),
|
||||
)?;
|
||||
let meta_cs = translate_slice::<SolAccountMeta>(
|
||||
memory_mapping,
|
||||
ix_c.accounts_addr,
|
||||
ix_c.accounts_len as u64,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size(),
|
||||
)?;
|
||||
let data = translate_slice::<u8>(
|
||||
memory_mapping,
|
||||
ix_c.data_addr,
|
||||
ix_c.data_len as u64,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size(),
|
||||
)?
|
||||
.to_vec();
|
||||
let accounts = meta_cs
|
||||
.iter()
|
||||
.map(|meta_c| {
|
||||
let pubkey = translate_type::<Pubkey>(
|
||||
memory_mapping,
|
||||
meta_c.pubkey_addr,
|
||||
invoke_context.get_check_aligned(),
|
||||
)?;
|
||||
Ok(AccountMeta {
|
||||
pubkey: *pubkey,
|
||||
is_signer: meta_c.is_signer,
|
||||
is_writable: meta_c.is_writable,
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<AccountMeta>, EbpfError<BpfError>>>()?;
|
||||
|
||||
Ok(Instruction {
|
||||
program_id: *program_id,
|
||||
accounts,
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
fn translate_accounts<'c>(
|
||||
&'c self,
|
||||
instruction_accounts: &[InstructionAccount],
|
||||
program_indices: &[usize],
|
||||
account_infos_addr: u64,
|
||||
account_infos_len: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
invoke_context: &mut InvokeContext,
|
||||
) -> Result<TranslatedAccounts<'c>, EbpfError<BpfError>> {
|
||||
let account_infos = translate_slice::<SolAccountInfo>(
|
||||
memory_mapping,
|
||||
account_infos_addr,
|
||||
account_infos_len,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size(),
|
||||
)?;
|
||||
check_account_infos(account_infos.len(), invoke_context)?;
|
||||
let account_info_keys = account_infos
|
||||
.iter()
|
||||
.map(|account_info| {
|
||||
translate_type::<Pubkey>(
|
||||
memory_mapping,
|
||||
account_info.key_addr,
|
||||
invoke_context.get_check_aligned(),
|
||||
)
|
||||
})
|
||||
.collect::<Result<Vec<_>, EbpfError<BpfError>>>()?;
|
||||
|
||||
let translate = |account_info: &SolAccountInfo, invoke_context: &InvokeContext| {
|
||||
// Translate the account from user space
|
||||
|
||||
let lamports = translate_type_mut::<u64>(
|
||||
memory_mapping,
|
||||
account_info.lamports_addr,
|
||||
invoke_context.get_check_aligned(),
|
||||
)?;
|
||||
let owner = translate_type_mut::<Pubkey>(
|
||||
memory_mapping,
|
||||
account_info.owner_addr,
|
||||
invoke_context.get_check_aligned(),
|
||||
)?;
|
||||
let vm_data_addr = account_info.data_addr;
|
||||
|
||||
invoke_context.get_compute_meter().consume(
|
||||
account_info
|
||||
.data_len
|
||||
.saturating_div(invoke_context.get_compute_budget().cpi_bytes_per_unit),
|
||||
)?;
|
||||
|
||||
let data = translate_slice_mut::<u8>(
|
||||
memory_mapping,
|
||||
vm_data_addr,
|
||||
account_info.data_len,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size(),
|
||||
)?;
|
||||
|
||||
let first_info_addr = account_infos.first().ok_or(SyscallError::InstructionError(
|
||||
InstructionError::InvalidArgument,
|
||||
))? as *const _ as u64;
|
||||
let addr = &account_info.data_len as *const u64 as u64;
|
||||
let vm_addr = if invoke_context
|
||||
.feature_set
|
||||
.is_active(&syscall_saturated_math::id())
|
||||
{
|
||||
account_infos_addr.saturating_add(addr.saturating_sub(first_info_addr))
|
||||
} else {
|
||||
#[allow(clippy::integer_arithmetic)]
|
||||
{
|
||||
account_infos_addr + (addr - first_info_addr)
|
||||
}
|
||||
};
|
||||
let _ = translate(
|
||||
memory_mapping,
|
||||
AccessType::Store,
|
||||
vm_addr,
|
||||
size_of::<u64>() as u64,
|
||||
)?;
|
||||
let ref_to_len_in_vm = unsafe { &mut *(addr as *mut u64) };
|
||||
|
||||
let ref_of_len_in_input_buffer =
|
||||
(account_info.data_addr as *mut u8 as u64).saturating_sub(8);
|
||||
let serialized_len_ptr = translate_type_mut::<u64>(
|
||||
memory_mapping,
|
||||
ref_of_len_in_input_buffer,
|
||||
invoke_context.get_check_aligned(),
|
||||
)?;
|
||||
|
||||
Ok(CallerAccount {
|
||||
lamports,
|
||||
owner,
|
||||
original_data_len: 0, // set later
|
||||
data,
|
||||
vm_data_addr,
|
||||
ref_to_len_in_vm,
|
||||
serialized_len_ptr,
|
||||
executable: account_info.executable,
|
||||
rent_epoch: account_info.rent_epoch,
|
||||
})
|
||||
};
|
||||
|
||||
get_translated_accounts(
|
||||
instruction_accounts,
|
||||
program_indices,
|
||||
&account_info_keys,
|
||||
account_infos,
|
||||
invoke_context,
|
||||
translate,
|
||||
)
|
||||
}
|
||||
|
||||
fn translate_signers(
|
||||
&self,
|
||||
program_id: &Pubkey,
|
||||
signers_seeds_addr: u64,
|
||||
signers_seeds_len: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
invoke_context: &InvokeContext,
|
||||
) -> Result<Vec<Pubkey>, EbpfError<BpfError>> {
|
||||
if signers_seeds_len > 0 {
|
||||
let signers_seeds = translate_slice::<SolSignerSeedsC>(
|
||||
memory_mapping,
|
||||
signers_seeds_addr,
|
||||
signers_seeds_len,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size(),
|
||||
)?;
|
||||
if signers_seeds.len() > MAX_SIGNERS {
|
||||
return Err(SyscallError::TooManySigners.into());
|
||||
}
|
||||
Ok(signers_seeds
|
||||
.iter()
|
||||
.map(|signer_seeds| {
|
||||
let seeds = translate_slice::<SolSignerSeedC>(
|
||||
memory_mapping,
|
||||
signer_seeds.addr,
|
||||
signer_seeds.len,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size(),
|
||||
)?;
|
||||
if seeds.len() > MAX_SEEDS {
|
||||
return Err(SyscallError::InstructionError(
|
||||
InstructionError::MaxSeedLengthExceeded,
|
||||
)
|
||||
.into());
|
||||
}
|
||||
let seeds_bytes = seeds
|
||||
.iter()
|
||||
.map(|seed| {
|
||||
translate_slice::<u8>(
|
||||
memory_mapping,
|
||||
seed.addr,
|
||||
seed.len,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size(),
|
||||
)
|
||||
})
|
||||
.collect::<Result<Vec<_>, EbpfError<BpfError>>>()?;
|
||||
Pubkey::create_program_address(&seeds_bytes, program_id)
|
||||
.map_err(|err| SyscallError::BadSeeds(err).into())
|
||||
})
|
||||
.collect::<Result<Vec<_>, EbpfError<BpfError>>>()?)
|
||||
} else {
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_translated_accounts<'a, T, F>(
|
||||
instruction_accounts: &[InstructionAccount],
|
||||
program_indices: &[usize],
|
||||
account_info_keys: &[&Pubkey],
|
||||
account_infos: &[T],
|
||||
invoke_context: &mut InvokeContext,
|
||||
do_translate: F,
|
||||
) -> Result<TranslatedAccounts<'a>, EbpfError<BpfError>>
|
||||
where
|
||||
F: Fn(&T, &InvokeContext) -> Result<CallerAccount<'a>, EbpfError<BpfError>>,
|
||||
{
|
||||
let transaction_context = &invoke_context.transaction_context;
|
||||
let instruction_context = transaction_context
|
||||
.get_current_instruction_context()
|
||||
.map_err(SyscallError::InstructionError)?;
|
||||
let mut accounts = Vec::with_capacity(instruction_accounts.len().saturating_add(1));
|
||||
|
||||
let program_account_index = program_indices
|
||||
.last()
|
||||
.ok_or(SyscallError::InstructionError(
|
||||
InstructionError::MissingAccount,
|
||||
))?;
|
||||
accounts.push((*program_account_index, None));
|
||||
|
||||
for (instruction_account_index, instruction_account) in instruction_accounts.iter().enumerate()
|
||||
{
|
||||
if instruction_account_index != instruction_account.index_in_callee {
|
||||
continue; // Skip duplicate account
|
||||
}
|
||||
let mut callee_account = instruction_context
|
||||
.try_borrow_instruction_account(
|
||||
transaction_context,
|
||||
instruction_account.index_in_caller,
|
||||
)
|
||||
.map_err(SyscallError::InstructionError)?;
|
||||
let account_key = invoke_context
|
||||
.transaction_context
|
||||
.get_key_of_account_at_index(instruction_account.index_in_transaction)
|
||||
.map_err(SyscallError::InstructionError)?;
|
||||
if callee_account.is_executable() {
|
||||
// Use the known account
|
||||
invoke_context.get_compute_meter().consume(
|
||||
(callee_account.get_data().len() as u64)
|
||||
.saturating_div(invoke_context.get_compute_budget().cpi_bytes_per_unit),
|
||||
)?;
|
||||
|
||||
accounts.push((instruction_account.index_in_caller, None));
|
||||
} else if let Some(caller_account_index) =
|
||||
account_info_keys.iter().position(|key| *key == account_key)
|
||||
{
|
||||
let mut caller_account = do_translate(
|
||||
account_infos
|
||||
.get(caller_account_index)
|
||||
.ok_or(SyscallError::InvalidLength)?,
|
||||
invoke_context,
|
||||
)?;
|
||||
{
|
||||
if callee_account.get_lamports() != *caller_account.lamports {
|
||||
callee_account
|
||||
.set_lamports(*caller_account.lamports)
|
||||
.map_err(SyscallError::InstructionError)?;
|
||||
}
|
||||
// The redundant check helps to avoid the expensive data comparison if we can
|
||||
match callee_account
|
||||
.can_data_be_resized(caller_account.data.len())
|
||||
.and_then(|_| callee_account.can_data_be_changed())
|
||||
{
|
||||
Ok(()) => callee_account
|
||||
.set_data(caller_account.data)
|
||||
.map_err(SyscallError::InstructionError)?,
|
||||
Err(err) if callee_account.get_data() != caller_account.data => {
|
||||
return Err(EbpfError::UserError(BpfError::SyscallError(
|
||||
SyscallError::InstructionError(err),
|
||||
)));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if callee_account.is_executable() != caller_account.executable {
|
||||
callee_account
|
||||
.set_executable(caller_account.executable)
|
||||
.map_err(SyscallError::InstructionError)?;
|
||||
}
|
||||
// Change the owner at the end so that we are allowed to change the lamports and data before
|
||||
if callee_account.get_owner() != caller_account.owner {
|
||||
callee_account
|
||||
.set_owner(caller_account.owner.as_ref())
|
||||
.map_err(SyscallError::InstructionError)?;
|
||||
}
|
||||
drop(callee_account);
|
||||
let callee_account = invoke_context
|
||||
.transaction_context
|
||||
.get_account_at_index(instruction_account.index_in_transaction)
|
||||
.map_err(SyscallError::InstructionError)?;
|
||||
if callee_account.borrow().rent_epoch() != caller_account.rent_epoch {
|
||||
if invoke_context
|
||||
.feature_set
|
||||
.is_active(&enable_early_verification_of_account_modifications::id())
|
||||
{
|
||||
Err(SyscallError::InstructionError(
|
||||
InstructionError::RentEpochModified,
|
||||
))?;
|
||||
} else {
|
||||
callee_account
|
||||
.borrow_mut()
|
||||
.set_rent_epoch(caller_account.rent_epoch);
|
||||
}
|
||||
}
|
||||
}
|
||||
let caller_account = if instruction_account.is_writable {
|
||||
let orig_data_lens = invoke_context
|
||||
.get_orig_account_lengths()
|
||||
.map_err(SyscallError::InstructionError)?;
|
||||
caller_account.original_data_len = *orig_data_lens
|
||||
.get(instruction_account.index_in_caller)
|
||||
.ok_or_else(|| {
|
||||
ic_msg!(
|
||||
invoke_context,
|
||||
"Internal error: index mismatch for account {}",
|
||||
account_key
|
||||
);
|
||||
SyscallError::InstructionError(InstructionError::MissingAccount)
|
||||
})?;
|
||||
Some(caller_account)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
accounts.push((instruction_account.index_in_caller, caller_account));
|
||||
} else {
|
||||
ic_msg!(
|
||||
invoke_context,
|
||||
"Instruction references an unknown account {}",
|
||||
account_key
|
||||
);
|
||||
return Err(SyscallError::InstructionError(InstructionError::MissingAccount).into());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(accounts)
|
||||
}
|
||||
|
||||
fn check_instruction_size(
|
||||
num_accounts: usize,
|
||||
data_len: usize,
|
||||
invoke_context: &mut InvokeContext,
|
||||
) -> Result<(), EbpfError<BpfError>> {
|
||||
let size = num_accounts
|
||||
.saturating_mul(size_of::<AccountMeta>())
|
||||
.saturating_add(data_len);
|
||||
let max_size = invoke_context.get_compute_budget().max_cpi_instruction_size;
|
||||
if size > max_size {
|
||||
return Err(SyscallError::InstructionTooLarge(size, max_size).into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_account_infos(
|
||||
len: usize,
|
||||
invoke_context: &mut InvokeContext,
|
||||
) -> Result<(), EbpfError<BpfError>> {
|
||||
let adjusted_len = if invoke_context
|
||||
.feature_set
|
||||
.is_active(&syscall_saturated_math::id())
|
||||
{
|
||||
len.saturating_mul(size_of::<Pubkey>())
|
||||
} else {
|
||||
#[allow(clippy::integer_arithmetic)]
|
||||
{
|
||||
len * size_of::<Pubkey>()
|
||||
}
|
||||
};
|
||||
if adjusted_len > invoke_context.get_compute_budget().max_cpi_instruction_size {
|
||||
// Cap the number of account_infos a caller can pass to approximate
|
||||
// maximum that accounts that could be passed in an instruction
|
||||
return Err(SyscallError::TooManyAccounts.into());
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_authorized_program(
|
||||
program_id: &Pubkey,
|
||||
instruction_data: &[u8],
|
||||
invoke_context: &InvokeContext,
|
||||
) -> Result<(), EbpfError<BpfError>> {
|
||||
#[allow(clippy::blocks_in_if_conditions)]
|
||||
if native_loader::check_id(program_id)
|
||||
|| bpf_loader::check_id(program_id)
|
||||
|| bpf_loader_deprecated::check_id(program_id)
|
||||
|| (bpf_loader_upgradeable::check_id(program_id)
|
||||
&& !(bpf_loader_upgradeable::is_upgrade_instruction(instruction_data)
|
||||
|| bpf_loader_upgradeable::is_set_authority_instruction(instruction_data)
|
||||
|| bpf_loader_upgradeable::is_close_instruction(instruction_data)))
|
||||
|| (invoke_context
|
||||
.feature_set
|
||||
.is_active(&prevent_calling_precompiles_as_programs::id())
|
||||
&& is_precompile(program_id, |feature_id: &Pubkey| {
|
||||
invoke_context.feature_set.is_active(feature_id)
|
||||
}))
|
||||
{
|
||||
return Err(SyscallError::ProgramNotSupported(*program_id).into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Call process instruction, common to both Rust and C
|
||||
fn call<'a, 'b: 'a>(
|
||||
syscall: &mut dyn SyscallInvokeSigned<'a, 'b>,
|
||||
instruction_addr: u64,
|
||||
account_infos_addr: u64,
|
||||
account_infos_len: u64,
|
||||
signers_seeds_addr: u64,
|
||||
signers_seeds_len: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
) -> Result<u64, EbpfError<BpfError>> {
|
||||
let mut invoke_context = syscall.get_context_mut()?;
|
||||
invoke_context
|
||||
.get_compute_meter()
|
||||
.consume(invoke_context.get_compute_budget().invoke_units)?;
|
||||
|
||||
// Translate and verify caller's data
|
||||
let instruction =
|
||||
syscall.translate_instruction(instruction_addr, memory_mapping, *invoke_context)?;
|
||||
let transaction_context = &invoke_context.transaction_context;
|
||||
let instruction_context = transaction_context
|
||||
.get_current_instruction_context()
|
||||
.map_err(SyscallError::InstructionError)?;
|
||||
let caller_program_id = instruction_context
|
||||
.get_last_program_key(transaction_context)
|
||||
.map_err(SyscallError::InstructionError)?;
|
||||
let signers = syscall.translate_signers(
|
||||
caller_program_id,
|
||||
signers_seeds_addr,
|
||||
signers_seeds_len,
|
||||
memory_mapping,
|
||||
*invoke_context,
|
||||
)?;
|
||||
let (instruction_accounts, program_indices) = invoke_context
|
||||
.prepare_instruction(&instruction, &signers)
|
||||
.map_err(SyscallError::InstructionError)?;
|
||||
check_authorized_program(&instruction.program_id, &instruction.data, *invoke_context)?;
|
||||
let mut accounts = syscall.translate_accounts(
|
||||
&instruction_accounts,
|
||||
&program_indices,
|
||||
account_infos_addr,
|
||||
account_infos_len,
|
||||
memory_mapping,
|
||||
*invoke_context,
|
||||
)?;
|
||||
|
||||
// Process instruction
|
||||
let mut compute_units_consumed = 0;
|
||||
invoke_context
|
||||
.process_instruction(
|
||||
&instruction.data,
|
||||
&instruction_accounts,
|
||||
&program_indices,
|
||||
&mut compute_units_consumed,
|
||||
&mut ExecuteTimings::default(),
|
||||
)
|
||||
.map_err(SyscallError::InstructionError)?;
|
||||
|
||||
// Copy results back to caller
|
||||
let transaction_context = &invoke_context.transaction_context;
|
||||
let instruction_context = transaction_context
|
||||
.get_current_instruction_context()
|
||||
.map_err(SyscallError::InstructionError)?;
|
||||
for (index_in_caller, caller_account) in accounts.iter_mut() {
|
||||
if let Some(caller_account) = caller_account {
|
||||
let callee_account = instruction_context
|
||||
.try_borrow_instruction_account(transaction_context, *index_in_caller)
|
||||
.map_err(SyscallError::InstructionError)?;
|
||||
*caller_account.lamports = callee_account.get_lamports();
|
||||
*caller_account.owner = *callee_account.get_owner();
|
||||
let new_len = callee_account.get_data().len();
|
||||
if caller_account.data.len() != new_len {
|
||||
let data_overflow = if invoke_context
|
||||
.feature_set
|
||||
.is_active(&syscall_saturated_math::id())
|
||||
{
|
||||
new_len
|
||||
> caller_account
|
||||
.original_data_len
|
||||
.saturating_add(MAX_PERMITTED_DATA_INCREASE)
|
||||
} else {
|
||||
#[allow(clippy::integer_arithmetic)]
|
||||
{
|
||||
new_len > caller_account.original_data_len + MAX_PERMITTED_DATA_INCREASE
|
||||
}
|
||||
};
|
||||
if data_overflow {
|
||||
ic_msg!(
|
||||
invoke_context,
|
||||
"Account data size realloc limited to {} in inner instructions",
|
||||
MAX_PERMITTED_DATA_INCREASE
|
||||
);
|
||||
return Err(
|
||||
SyscallError::InstructionError(InstructionError::InvalidRealloc).into(),
|
||||
);
|
||||
}
|
||||
if new_len < caller_account.data.len() {
|
||||
caller_account
|
||||
.data
|
||||
.get_mut(new_len..)
|
||||
.ok_or(SyscallError::InstructionError(
|
||||
InstructionError::AccountDataTooSmall,
|
||||
))?
|
||||
.fill(0);
|
||||
}
|
||||
caller_account.data = translate_slice_mut::<u8>(
|
||||
memory_mapping,
|
||||
caller_account.vm_data_addr,
|
||||
new_len as u64,
|
||||
false, // Don't care since it is byte aligned
|
||||
invoke_context.get_check_size(),
|
||||
)?;
|
||||
*caller_account.ref_to_len_in_vm = new_len as u64;
|
||||
*caller_account.serialized_len_ptr = new_len as u64;
|
||||
}
|
||||
let to_slice = &mut caller_account.data;
|
||||
let from_slice = callee_account
|
||||
.get_data()
|
||||
.get(0..new_len)
|
||||
.ok_or(SyscallError::InvalidLength)?;
|
||||
if to_slice.len() != from_slice.len() {
|
||||
return Err(
|
||||
SyscallError::InstructionError(InstructionError::AccountDataTooSmall).into(),
|
||||
);
|
||||
}
|
||||
to_slice.copy_from_slice(from_slice);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(SUCCESS)
|
||||
}
|
|
@ -0,0 +1,222 @@
|
|||
use {super::*, crate::declare_syscall};
|
||||
|
||||
declare_syscall!(
|
||||
/// Log a user's info message
|
||||
SyscallLog,
|
||||
fn call(
|
||||
&mut self,
|
||||
addr: u64,
|
||||
len: u64,
|
||||
_arg3: u64,
|
||||
_arg4: u64,
|
||||
_arg5: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
result: &mut Result<u64, EbpfError<BpfError>>,
|
||||
) {
|
||||
let invoke_context = question_mark!(
|
||||
self.invoke_context
|
||||
.try_borrow()
|
||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
|
||||
result
|
||||
);
|
||||
let cost = invoke_context
|
||||
.get_compute_budget()
|
||||
.syscall_base_cost
|
||||
.max(len);
|
||||
question_mark!(invoke_context.get_compute_meter().consume(cost), result);
|
||||
|
||||
question_mark!(
|
||||
translate_string_and_do(
|
||||
memory_mapping,
|
||||
addr,
|
||||
len,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size(),
|
||||
&mut |string: &str| {
|
||||
stable_log::program_log(&invoke_context.get_log_collector(), string);
|
||||
Ok(0)
|
||||
}
|
||||
),
|
||||
result
|
||||
);
|
||||
*result = Ok(0);
|
||||
}
|
||||
);
|
||||
|
||||
declare_syscall!(
|
||||
/// Log 5 64-bit values
|
||||
SyscallLogU64,
|
||||
fn call(
|
||||
&mut self,
|
||||
arg1: u64,
|
||||
arg2: u64,
|
||||
arg3: u64,
|
||||
arg4: u64,
|
||||
arg5: u64,
|
||||
_memory_mapping: &mut MemoryMapping,
|
||||
result: &mut Result<u64, EbpfError<BpfError>>,
|
||||
) {
|
||||
let invoke_context = question_mark!(
|
||||
self.invoke_context
|
||||
.try_borrow()
|
||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
|
||||
result
|
||||
);
|
||||
let cost = invoke_context.get_compute_budget().log_64_units;
|
||||
question_mark!(invoke_context.get_compute_meter().consume(cost), result);
|
||||
|
||||
stable_log::program_log(
|
||||
&invoke_context.get_log_collector(),
|
||||
&format!(
|
||||
"{:#x}, {:#x}, {:#x}, {:#x}, {:#x}",
|
||||
arg1, arg2, arg3, arg4, arg5
|
||||
),
|
||||
);
|
||||
*result = Ok(0);
|
||||
}
|
||||
);
|
||||
|
||||
declare_syscall!(
|
||||
/// Log current compute consumption
|
||||
SyscallLogBpfComputeUnits,
|
||||
fn call(
|
||||
&mut self,
|
||||
_arg1: u64,
|
||||
_arg2: u64,
|
||||
_arg3: u64,
|
||||
_arg4: u64,
|
||||
_arg5: u64,
|
||||
_memory_mapping: &mut MemoryMapping,
|
||||
result: &mut Result<u64, EbpfError<BpfError>>,
|
||||
) {
|
||||
let invoke_context = question_mark!(
|
||||
self.invoke_context
|
||||
.try_borrow()
|
||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
|
||||
result
|
||||
);
|
||||
let cost = invoke_context.get_compute_budget().syscall_base_cost;
|
||||
question_mark!(invoke_context.get_compute_meter().consume(cost), result);
|
||||
|
||||
ic_logger_msg!(
|
||||
invoke_context.get_log_collector(),
|
||||
"Program consumption: {} units remaining",
|
||||
invoke_context.get_compute_meter().borrow().get_remaining()
|
||||
);
|
||||
*result = Ok(0);
|
||||
}
|
||||
);
|
||||
|
||||
declare_syscall!(
|
||||
/// Log 5 64-bit values
|
||||
SyscallLogPubkey,
|
||||
fn call(
|
||||
&mut self,
|
||||
pubkey_addr: u64,
|
||||
_arg2: u64,
|
||||
_arg3: u64,
|
||||
_arg4: u64,
|
||||
_arg5: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
result: &mut Result<u64, EbpfError<BpfError>>,
|
||||
) {
|
||||
let invoke_context = question_mark!(
|
||||
self.invoke_context
|
||||
.try_borrow()
|
||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
|
||||
result
|
||||
);
|
||||
let cost = invoke_context.get_compute_budget().log_pubkey_units;
|
||||
question_mark!(invoke_context.get_compute_meter().consume(cost), result);
|
||||
|
||||
let pubkey = question_mark!(
|
||||
translate_type::<Pubkey>(
|
||||
memory_mapping,
|
||||
pubkey_addr,
|
||||
invoke_context.get_check_aligned()
|
||||
),
|
||||
result
|
||||
);
|
||||
stable_log::program_log(&invoke_context.get_log_collector(), &pubkey.to_string());
|
||||
*result = Ok(0);
|
||||
}
|
||||
);
|
||||
|
||||
declare_syscall!(
|
||||
/// Log data handling
|
||||
SyscallLogData,
|
||||
fn call(
|
||||
&mut self,
|
||||
addr: u64,
|
||||
len: u64,
|
||||
_arg3: u64,
|
||||
_arg4: u64,
|
||||
_arg5: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
result: &mut Result<u64, EbpfError<BpfError>>,
|
||||
) {
|
||||
let invoke_context = question_mark!(
|
||||
self.invoke_context
|
||||
.try_borrow()
|
||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
|
||||
result
|
||||
);
|
||||
let budget = invoke_context.get_compute_budget();
|
||||
|
||||
question_mark!(
|
||||
invoke_context
|
||||
.get_compute_meter()
|
||||
.consume(budget.syscall_base_cost),
|
||||
result
|
||||
);
|
||||
|
||||
let untranslated_fields = question_mark!(
|
||||
translate_slice::<&[u8]>(
|
||||
memory_mapping,
|
||||
addr,
|
||||
len,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size(),
|
||||
),
|
||||
result
|
||||
);
|
||||
|
||||
question_mark!(
|
||||
invoke_context.get_compute_meter().consume(
|
||||
budget
|
||||
.syscall_base_cost
|
||||
.saturating_mul(untranslated_fields.len() as u64)
|
||||
),
|
||||
result
|
||||
);
|
||||
question_mark!(
|
||||
invoke_context.get_compute_meter().consume(
|
||||
untranslated_fields
|
||||
.iter()
|
||||
.fold(0, |total, e| total.saturating_add(e.len() as u64))
|
||||
),
|
||||
result
|
||||
);
|
||||
|
||||
let mut fields = Vec::with_capacity(untranslated_fields.len());
|
||||
|
||||
for untranslated_field in untranslated_fields {
|
||||
fields.push(question_mark!(
|
||||
translate_slice::<u8>(
|
||||
memory_mapping,
|
||||
untranslated_field.as_ptr() as *const _ as u64,
|
||||
untranslated_field.len() as u64,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size(),
|
||||
),
|
||||
result
|
||||
));
|
||||
}
|
||||
|
||||
let log_collector = invoke_context.get_log_collector();
|
||||
|
||||
stable_log::program_data(&log_collector, &fields);
|
||||
|
||||
*result = Ok(0);
|
||||
}
|
||||
);
|
|
@ -0,0 +1,240 @@
|
|||
use {super::*, crate::declare_syscall};
|
||||
|
||||
fn mem_op_consume<'a, 'b>(
|
||||
invoke_context: &Ref<&'a mut InvokeContext<'b>>,
|
||||
n: u64,
|
||||
) -> Result<(), EbpfError<BpfError>> {
|
||||
let compute_budget = invoke_context.get_compute_budget();
|
||||
let cost = compute_budget
|
||||
.mem_op_base_cost
|
||||
.max(n.saturating_div(compute_budget.cpi_bytes_per_unit));
|
||||
invoke_context.get_compute_meter().consume(cost)
|
||||
}
|
||||
|
||||
declare_syscall!(
|
||||
/// memcpy
|
||||
SyscallMemcpy,
|
||||
fn call(
|
||||
&mut self,
|
||||
dst_addr: u64,
|
||||
src_addr: u64,
|
||||
n: u64,
|
||||
_arg4: u64,
|
||||
_arg5: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
result: &mut Result<u64, EbpfError<BpfError>>,
|
||||
) {
|
||||
let invoke_context = question_mark!(
|
||||
self.invoke_context
|
||||
.try_borrow()
|
||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
|
||||
result
|
||||
);
|
||||
question_mark!(mem_op_consume(&invoke_context, n), result);
|
||||
|
||||
let do_check_physical_overlapping = invoke_context
|
||||
.feature_set
|
||||
.is_active(&check_physical_overlapping::id());
|
||||
|
||||
if !is_nonoverlapping(src_addr, dst_addr, n) {
|
||||
*result = Err(SyscallError::CopyOverlapping.into());
|
||||
return;
|
||||
}
|
||||
|
||||
let dst_ptr = question_mark!(
|
||||
translate_slice_mut::<u8>(
|
||||
memory_mapping,
|
||||
dst_addr,
|
||||
n,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size()
|
||||
),
|
||||
result
|
||||
)
|
||||
.as_mut_ptr();
|
||||
let src_ptr = question_mark!(
|
||||
translate_slice::<u8>(
|
||||
memory_mapping,
|
||||
src_addr,
|
||||
n,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size()
|
||||
),
|
||||
result
|
||||
)
|
||||
.as_ptr();
|
||||
if do_check_physical_overlapping
|
||||
&& !is_nonoverlapping(src_ptr as usize, dst_ptr as usize, n as usize)
|
||||
{
|
||||
unsafe {
|
||||
std::ptr::copy(src_ptr, dst_ptr, n as usize);
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
std::ptr::copy_nonoverlapping(src_ptr, dst_ptr, n as usize);
|
||||
}
|
||||
}
|
||||
*result = Ok(0);
|
||||
}
|
||||
);
|
||||
|
||||
declare_syscall!(
|
||||
/// memmove
|
||||
SyscallMemmove,
|
||||
fn call(
|
||||
&mut self,
|
||||
dst_addr: u64,
|
||||
src_addr: u64,
|
||||
n: u64,
|
||||
_arg4: u64,
|
||||
_arg5: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
result: &mut Result<u64, EbpfError<BpfError>>,
|
||||
) {
|
||||
let invoke_context = question_mark!(
|
||||
self.invoke_context
|
||||
.try_borrow()
|
||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
|
||||
result
|
||||
);
|
||||
question_mark!(mem_op_consume(&invoke_context, n), result);
|
||||
|
||||
let dst = question_mark!(
|
||||
translate_slice_mut::<u8>(
|
||||
memory_mapping,
|
||||
dst_addr,
|
||||
n,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size()
|
||||
),
|
||||
result
|
||||
);
|
||||
let src = question_mark!(
|
||||
translate_slice::<u8>(
|
||||
memory_mapping,
|
||||
src_addr,
|
||||
n,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size()
|
||||
),
|
||||
result
|
||||
);
|
||||
unsafe {
|
||||
std::ptr::copy(src.as_ptr(), dst.as_mut_ptr(), n as usize);
|
||||
}
|
||||
*result = Ok(0);
|
||||
}
|
||||
);
|
||||
|
||||
declare_syscall!(
|
||||
/// memcmp
|
||||
SyscallMemcmp,
|
||||
fn call(
|
||||
&mut self,
|
||||
s1_addr: u64,
|
||||
s2_addr: u64,
|
||||
n: u64,
|
||||
cmp_result_addr: u64,
|
||||
_arg5: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
result: &mut Result<u64, EbpfError<BpfError>>,
|
||||
) {
|
||||
let invoke_context = question_mark!(
|
||||
self.invoke_context
|
||||
.try_borrow()
|
||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
|
||||
result
|
||||
);
|
||||
question_mark!(mem_op_consume(&invoke_context, n), result);
|
||||
|
||||
let s1 = question_mark!(
|
||||
translate_slice::<u8>(
|
||||
memory_mapping,
|
||||
s1_addr,
|
||||
n,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size(),
|
||||
),
|
||||
result
|
||||
);
|
||||
let s2 = question_mark!(
|
||||
translate_slice::<u8>(
|
||||
memory_mapping,
|
||||
s2_addr,
|
||||
n,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size(),
|
||||
),
|
||||
result
|
||||
);
|
||||
let cmp_result = question_mark!(
|
||||
translate_type_mut::<i32>(
|
||||
memory_mapping,
|
||||
cmp_result_addr,
|
||||
invoke_context.get_check_aligned()
|
||||
),
|
||||
result
|
||||
);
|
||||
let mut i = 0;
|
||||
while i < n as usize {
|
||||
let a = *question_mark!(s1.get(i).ok_or(SyscallError::InvalidLength,), result);
|
||||
let b = *question_mark!(s2.get(i).ok_or(SyscallError::InvalidLength,), result);
|
||||
if a != b {
|
||||
*cmp_result = if invoke_context
|
||||
.feature_set
|
||||
.is_active(&syscall_saturated_math::id())
|
||||
{
|
||||
(a as i32).saturating_sub(b as i32)
|
||||
} else {
|
||||
#[allow(clippy::integer_arithmetic)]
|
||||
{
|
||||
a as i32 - b as i32
|
||||
}
|
||||
};
|
||||
*result = Ok(0);
|
||||
return;
|
||||
};
|
||||
i = i.saturating_add(1);
|
||||
}
|
||||
*cmp_result = 0;
|
||||
*result = Ok(0);
|
||||
}
|
||||
);
|
||||
|
||||
declare_syscall!(
|
||||
/// memset
|
||||
SyscallMemset,
|
||||
fn call(
|
||||
&mut self,
|
||||
s_addr: u64,
|
||||
c: u64,
|
||||
n: u64,
|
||||
_arg4: u64,
|
||||
_arg5: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
result: &mut Result<u64, EbpfError<BpfError>>,
|
||||
) {
|
||||
let invoke_context = question_mark!(
|
||||
self.invoke_context
|
||||
.try_borrow()
|
||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
|
||||
result
|
||||
);
|
||||
question_mark!(mem_op_consume(&invoke_context, n), result);
|
||||
|
||||
let s = question_mark!(
|
||||
translate_slice_mut::<u8>(
|
||||
memory_mapping,
|
||||
s_addr,
|
||||
n,
|
||||
invoke_context.get_check_aligned(),
|
||||
invoke_context.get_check_size(),
|
||||
),
|
||||
result
|
||||
);
|
||||
for val in s.iter_mut().take(n as usize) {
|
||||
*val = c as u8;
|
||||
}
|
||||
*result = Ok(0);
|
||||
}
|
||||
);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,141 @@
|
|||
use {super::*, crate::declare_syscall};
|
||||
|
||||
fn get_sysvar<T: std::fmt::Debug + Sysvar + SysvarId + Clone>(
|
||||
sysvar: Result<Arc<T>, InstructionError>,
|
||||
var_addr: u64,
|
||||
check_aligned: bool,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
invoke_context: &mut InvokeContext,
|
||||
) -> Result<u64, EbpfError<BpfError>> {
|
||||
invoke_context.get_compute_meter().consume(
|
||||
invoke_context
|
||||
.get_compute_budget()
|
||||
.sysvar_base_cost
|
||||
.saturating_add(size_of::<T>() as u64),
|
||||
)?;
|
||||
let var = translate_type_mut::<T>(memory_mapping, var_addr, check_aligned)?;
|
||||
|
||||
let sysvar: Arc<T> = sysvar.map_err(SyscallError::InstructionError)?;
|
||||
*var = T::clone(sysvar.as_ref());
|
||||
|
||||
Ok(SUCCESS)
|
||||
}
|
||||
|
||||
declare_syscall!(
|
||||
/// Get a Clock sysvar
|
||||
SyscallGetClockSysvar,
|
||||
fn call(
|
||||
&mut self,
|
||||
var_addr: u64,
|
||||
_arg2: u64,
|
||||
_arg3: u64,
|
||||
_arg4: u64,
|
||||
_arg5: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
result: &mut Result<u64, EbpfError<BpfError>>,
|
||||
) {
|
||||
let mut invoke_context = question_mark!(
|
||||
self.invoke_context
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
|
||||
result
|
||||
);
|
||||
*result = get_sysvar(
|
||||
invoke_context.get_sysvar_cache().get_clock(),
|
||||
var_addr,
|
||||
invoke_context.get_check_aligned(),
|
||||
memory_mapping,
|
||||
&mut invoke_context,
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
declare_syscall!(
|
||||
/// Get a EpochSchedule sysvar
|
||||
SyscallGetEpochScheduleSysvar,
|
||||
fn call(
|
||||
&mut self,
|
||||
var_addr: u64,
|
||||
_arg2: u64,
|
||||
_arg3: u64,
|
||||
_arg4: u64,
|
||||
_arg5: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
result: &mut Result<u64, EbpfError<BpfError>>,
|
||||
) {
|
||||
let mut invoke_context = question_mark!(
|
||||
self.invoke_context
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
|
||||
result
|
||||
);
|
||||
*result = get_sysvar(
|
||||
invoke_context.get_sysvar_cache().get_epoch_schedule(),
|
||||
var_addr,
|
||||
invoke_context.get_check_aligned(),
|
||||
memory_mapping,
|
||||
&mut invoke_context,
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
declare_syscall!(
|
||||
/// Get a Fees sysvar
|
||||
SyscallGetFeesSysvar,
|
||||
fn call(
|
||||
&mut self,
|
||||
var_addr: u64,
|
||||
_arg2: u64,
|
||||
_arg3: u64,
|
||||
_arg4: u64,
|
||||
_arg5: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
result: &mut Result<u64, EbpfError<BpfError>>,
|
||||
) {
|
||||
let mut invoke_context = question_mark!(
|
||||
self.invoke_context
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
|
||||
result
|
||||
);
|
||||
#[allow(deprecated)]
|
||||
{
|
||||
*result = get_sysvar(
|
||||
invoke_context.get_sysvar_cache().get_fees(),
|
||||
var_addr,
|
||||
invoke_context.get_check_aligned(),
|
||||
memory_mapping,
|
||||
&mut invoke_context,
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
declare_syscall!(
|
||||
/// Get a Rent sysvar
|
||||
SyscallGetRentSysvar,
|
||||
fn call(
|
||||
&mut self,
|
||||
var_addr: u64,
|
||||
_arg2: u64,
|
||||
_arg3: u64,
|
||||
_arg4: u64,
|
||||
_arg5: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
result: &mut Result<u64, EbpfError<BpfError>>,
|
||||
) {
|
||||
let mut invoke_context = question_mark!(
|
||||
self.invoke_context
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
|
||||
result
|
||||
);
|
||||
*result = get_sysvar(
|
||||
invoke_context.get_sysvar_cache().get_rent(),
|
||||
var_addr,
|
||||
invoke_context.get_check_aligned(),
|
||||
memory_mapping,
|
||||
&mut invoke_context,
|
||||
);
|
||||
}
|
||||
);
|
Loading…
Reference in New Issue