From cebf52d94da8f7b83788f71b783535d255753b88 Mon Sep 17 00:00:00 2001 From: Joe C Date: Tue, 30 Apr 2024 19:14:27 -0500 Subject: [PATCH] syscall: get-epoch-stake --- programs/bpf_loader/src/syscalls/mod.rs | 50 ++++++++++++++++++++++++- sdk/program/src/epoch_stake.rs | 21 +++++++++++ sdk/program/src/lib.rs | 1 + sdk/program/src/program_stubs.rs | 10 +++++ sdk/program/src/syscalls/definitions.rs | 1 + 5 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 sdk/program/src/epoch_stake.rs diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index b71e60ca7d4161..d316c3a725757b 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)?; @@ -1997,6 +2008,41 @@ 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_vote_accounts() + .get(vote_address) + .map(|(stake, _)| *stake) + .unwrap_or(0); + + Ok(0) + } +); + #[cfg(test)] #[allow(clippy::arithmetic_side_effects)] #[allow(clippy::indexing_slicing)] diff --git a/sdk/program/src/epoch_stake.rs b/sdk/program/src/epoch_stake.rs new file mode 100644 index 00000000000000..bf10c97977275e --- /dev/null +++ b/sdk/program/src/epoch_stake.rs @@ -0,0 +1,21 @@ +use crate::{program_error::ProgramError, pubkey::Pubkey}; + +/// Get the current epoch stake for a given vote account. +/// Returns `0` for any provided pubkey that isn't a vote account. +pub fn get_epoch_stake(vote_address: &Pubkey) -> 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()), + } +} diff --git a/sdk/program/src/lib.rs b/sdk/program/src/lib.rs index 1f464337028287..b5a3840f84de28 100644 --- a/sdk/program/src/lib.rs +++ b/sdk/program/src/lib.rs @@ -491,6 +491,7 @@ pub mod entrypoint; pub mod entrypoint_deprecated; pub mod epoch_rewards; pub mod epoch_schedule; +pub mod epoch_stake; pub mod feature; pub mod fee_calculator; pub mod hash; 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 {