diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index 63e15171a7af5d..b8424b27815783 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -38,8 +38,9 @@ use { disable_deploy_of_alloc_free_syscall, disable_fees_sysvar, enable_alt_bn128_compression_syscall, enable_alt_bn128_syscall, enable_big_mod_exp_syscall, enable_partitioned_epoch_reward, enable_poseidon_syscall, - error_on_syscall_bpf_function_hash_collisions, last_restart_slot_sysvar, - reject_callx_r10, remaining_compute_units_syscall_enabled, switch_to_new_elf_parser, + enable_syscall_get_epoch_stake, error_on_syscall_bpf_function_hash_collisions, + last_restart_slot_sysvar, reject_callx_r10, remaining_compute_units_syscall_enabled, + switch_to_new_elf_parser, }, hash::{Hash, Hasher}, instruction::{AccountMeta, InstructionError, ProcessedSiblingInstruction}, @@ -278,6 +279,8 @@ pub fn create_program_runtime_environment_v1<'a>( let enable_poseidon_syscall = feature_set.is_active(&enable_poseidon_syscall::id()); let remaining_compute_units_syscall_enabled = feature_set.is_active(&remaining_compute_units_syscall_enabled::id()); + let enable_syscall_get_epoch_stake = + feature_set.is_active(&enable_syscall_get_epoch_stake::id()); // !!! ATTENTION !!! // When adding new features for RBPF here, // also add them to `Bank::apply_builtin_program_feature_transitions()`. @@ -464,6 +467,14 @@ pub fn create_program_runtime_environment_v1<'a>( SyscallAltBn128Compression::vm, )?; + // Get Epoch Stake + register_feature_gated_function!( + result, + enable_syscall_get_epoch_stake, + *b"sol_syscall_get_epoch_stake", + SyscallGetEpochStake::vm, + )?; + // Log data result.register_function_hashed(*b"sol_log_data", SyscallLogData::vm)?; @@ -1958,6 +1969,37 @@ declare_builtin_function!( } ); +declare_builtin_function!( + // Get Epoch Stake Syscall + SyscallGetEpochStake, + fn rust( + invoke_context: &mut InvokeContext, + var_addr: u64, + vote_address: u64, + _arg3: u64, + _arg4: u64, + _arg5: u64, + memory_mapping: &mut MemoryMapping, + ) -> Result { + let compute_budget = invoke_context.get_compute_budget(); + let div_by_cpi = |n: u64| -> u64 { + n.checked_div(compute_budget.cpi_bytes_per_unit) + .unwrap_or(u64::MAX) + }; + consume_compute_meter(invoke_context, div_by_cpi(32).saturating_add(div_by_cpi(8)))?; + + let check_aligned = invoke_context.get_check_aligned(); + + let vote_address = translate_type::(memory_mapping, vote_address, check_aligned)?; + + let var = translate_type_mut::(memory_mapping, var_addr, check_aligned)?; + + *var = (invoke_context.get_epoch_stake_callback)(vote_address); + + Ok(0) + } +); + #[cfg(test)] #[allow(clippy::arithmetic_side_effects)] #[allow(clippy::indexing_slicing)] diff --git a/sdk/program/src/entrypoint.rs b/sdk/program/src/entrypoint.rs index d0d579411dcfe8..a115d21a6c3701 100644 --- a/sdk/program/src/entrypoint.rs +++ b/sdk/program/src/entrypoint.rs @@ -370,6 +370,27 @@ pub unsafe fn deserialize<'a>(input: *mut u8) -> (&'a Pubkey, Vec Result { + let mut var = 0u64; + let var_addr = &mut var as *mut _ as *mut u8; + + let vote_address = vote_address as *const _ as *const u8; + + #[cfg(target_os = "solana")] + let result = unsafe { crate::syscalls::sol_syscall_get_epoch_stake(var_addr, vote_address) }; + + #[cfg(not(target_os = "solana"))] + let result = crate::program_stubs::sol_syscall_get_epoch_stake(var_addr, vote_address); + + match result { + crate::entrypoint::SUCCESS => Ok(var), + e => Err(e.into()), + } +} + #[cfg(test)] mod test { use {super::*, std::alloc::GlobalAlloc}; diff --git a/sdk/program/src/program_stubs.rs b/sdk/program/src/program_stubs.rs index cf890659fa68a1..14d4ebd356caf5 100644 --- a/sdk/program/src/program_stubs.rs +++ b/sdk/program/src/program_stubs.rs @@ -61,6 +61,9 @@ pub trait SyscallStubs: Sync + Send { fn sol_get_last_restart_slot(&self, _var_addr: *mut u8) -> u64 { UNSUPPORTED_SYSVAR } + fn sol_syscall_get_epoch_stake(&self, _var_addr: *mut u8, _vote_address: *const u8) -> u64 { + UNSUPPORTED_SYSVAR + } /// # Safety unsafe fn sol_memcpy(&self, dst: *mut u8, src: *const u8, n: usize) { // cannot be overlapping @@ -171,6 +174,13 @@ pub(crate) fn sol_get_last_restart_slot(var_addr: *mut u8) -> u64 { .sol_get_last_restart_slot(var_addr) } +pub(crate) fn sol_syscall_get_epoch_stake(var_addr: *mut u8, vote_address: *const u8) -> u64 { + SYSCALL_STUBS + .read() + .unwrap() + .sol_syscall_get_epoch_stake(var_addr, vote_address) +} + pub(crate) fn sol_memcpy(dst: *mut u8, src: *const u8, n: usize) { unsafe { SYSCALL_STUBS.read().unwrap().sol_memcpy(dst, src, n); diff --git a/sdk/program/src/syscalls/definitions.rs b/sdk/program/src/syscalls/definitions.rs index b2dedceba953a0..534b53882af217 100644 --- a/sdk/program/src/syscalls/definitions.rs +++ b/sdk/program/src/syscalls/definitions.rs @@ -72,6 +72,7 @@ define_syscall!(fn sol_get_epoch_rewards_sysvar(addr: *mut u8) -> u64); define_syscall!(fn sol_poseidon(parameters: u64, endianness: u64, vals: *const u8, val_len: u64, hash_result: *mut u8) -> u64); define_syscall!(fn sol_remaining_compute_units() -> u64); define_syscall!(fn sol_alt_bn128_compression(op: u64, input: *const u8, input_size: u64, result: *mut u8) -> u64); +define_syscall!(fn sol_syscall_get_epoch_stake(addr: *mut u8, vote_address: *const u8) -> u64); #[cfg(target_feature = "static-syscalls")] pub const fn sys_hash(name: &str) -> usize {