Return sysvars via syscalls (#16422)
This commit is contained in:
@ -82,7 +82,7 @@ pub type UnixTimestamp = i64;
|
||||
/// as the network progresses).
|
||||
///
|
||||
#[repr(C)]
|
||||
#[derive(Serialize, Deserialize, Debug, Default, PartialEq)]
|
||||
#[derive(Serialize, Clone, Deserialize, Debug, Default, PartialEq)]
|
||||
pub struct Clock {
|
||||
/// the current network/bank Slot
|
||||
pub slot: Slot,
|
||||
|
@ -2,7 +2,10 @@
|
||||
|
||||
#![cfg(not(target_arch = "bpf"))]
|
||||
|
||||
use crate::{account_info::AccountInfo, entrypoint::ProgramResult, instruction::Instruction};
|
||||
use crate::{
|
||||
account_info::AccountInfo, entrypoint::ProgramResult, instruction::Instruction,
|
||||
program_error::UNSUPPORTED_SYSVAR,
|
||||
};
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
@ -31,6 +34,19 @@ pub trait SyscallStubs: Sync + Send {
|
||||
sol_log("SyscallStubs: sol_invoke_signed() not available");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sol_get_clock_sysvar(&self, _var_addr: *mut u8) -> u64 {
|
||||
UNSUPPORTED_SYSVAR
|
||||
}
|
||||
fn sol_get_epoch_schedule_sysvar(&self, _var_addr: *mut u8) -> u64 {
|
||||
UNSUPPORTED_SYSVAR
|
||||
}
|
||||
fn sol_get_fees_sysvar(&self, _var_addr: *mut u8) -> u64 {
|
||||
UNSUPPORTED_SYSVAR
|
||||
}
|
||||
fn sol_get_rent_sysvar(&self, _var_addr: *mut u8) -> u64 {
|
||||
UNSUPPORTED_SYSVAR
|
||||
}
|
||||
}
|
||||
|
||||
struct DefaultSyscallStubs {}
|
||||
@ -61,3 +77,22 @@ pub(crate) fn sol_invoke_signed(
|
||||
.unwrap()
|
||||
.sol_invoke_signed(instruction, account_infos, signers_seeds)
|
||||
}
|
||||
|
||||
pub(crate) fn sol_get_clock_sysvar(var_addr: *mut u8) -> u64 {
|
||||
SYSCALL_STUBS.read().unwrap().sol_get_clock_sysvar(var_addr)
|
||||
}
|
||||
|
||||
pub(crate) fn sol_get_epoch_schedule_sysvar(var_addr: *mut u8) -> u64 {
|
||||
SYSCALL_STUBS
|
||||
.read()
|
||||
.unwrap()
|
||||
.sol_get_epoch_schedule_sysvar(var_addr)
|
||||
}
|
||||
|
||||
pub(crate) fn sol_get_fees_sysvar(var_addr: *mut u8) -> u64 {
|
||||
SYSCALL_STUBS.read().unwrap().sol_get_fees_sysvar(var_addr)
|
||||
}
|
||||
|
||||
pub(crate) fn sol_get_rent_sysvar(var_addr: *mut u8) -> u64 {
|
||||
SYSCALL_STUBS.read().unwrap().sol_get_rent_sysvar(var_addr)
|
||||
}
|
||||
|
@ -2,8 +2,10 @@
|
||||
//!
|
||||
pub use crate::clock::Clock;
|
||||
|
||||
use crate::sysvar::Sysvar;
|
||||
use crate::{impl_sysvar_get, program_error::ProgramError, sysvar::Sysvar};
|
||||
|
||||
crate::declare_sysvar_id!("SysvarC1ock11111111111111111111111111111111", Clock);
|
||||
|
||||
impl Sysvar for Clock {}
|
||||
impl Sysvar for Clock {
|
||||
impl_sysvar_get!(sol_get_clock_sysvar);
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
//! This account contains the current cluster rent
|
||||
//!
|
||||
pub use crate::epoch_schedule::EpochSchedule;
|
||||
use crate::sysvar::Sysvar;
|
||||
|
||||
use crate::{impl_sysvar_get, program_error::ProgramError, sysvar::Sysvar};
|
||||
|
||||
crate::declare_sysvar_id!("SysvarEpochSchedu1e111111111111111111111111", EpochSchedule);
|
||||
|
||||
impl Sysvar for EpochSchedule {}
|
||||
impl Sysvar for EpochSchedule {
|
||||
impl_sysvar_get!(sol_get_epoch_schedule_sysvar);
|
||||
}
|
||||
|
@ -1,11 +1,13 @@
|
||||
//! This account contains the current cluster fees
|
||||
//!
|
||||
use crate::{fee_calculator::FeeCalculator, sysvar::Sysvar};
|
||||
use crate::{
|
||||
fee_calculator::FeeCalculator, impl_sysvar_get, program_error::ProgramError, sysvar::Sysvar,
|
||||
};
|
||||
|
||||
crate::declare_sysvar_id!("SysvarFees111111111111111111111111111111111", Fees);
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
|
||||
pub struct Fees {
|
||||
pub fee_calculator: FeeCalculator,
|
||||
}
|
||||
@ -17,4 +19,6 @@ impl Fees {
|
||||
}
|
||||
}
|
||||
|
||||
impl Sysvar for Fees {}
|
||||
impl Sysvar for Fees {
|
||||
impl_sysvar_get!(sol_get_fees_sysvar);
|
||||
}
|
||||
|
@ -47,14 +47,14 @@ macro_rules! declare_sysvar_id(
|
||||
)
|
||||
);
|
||||
|
||||
// owner pubkey for sysvar accounts
|
||||
// Owner pubkey for sysvar accounts
|
||||
crate::declare_id!("Sysvar1111111111111111111111111111111111111");
|
||||
|
||||
pub trait SysvarId {
|
||||
fn check_id(pubkey: &Pubkey) -> bool;
|
||||
}
|
||||
|
||||
// utilities for moving into and out of Accounts
|
||||
// Sysvar utilities
|
||||
pub trait Sysvar:
|
||||
SysvarId + Default + Sized + serde::Serialize + serde::de::DeserializeOwned
|
||||
{
|
||||
@ -70,6 +70,34 @@ pub trait Sysvar:
|
||||
fn to_account_info(&self, account_info: &mut AccountInfo) -> Option<()> {
|
||||
bincode::serialize_into(&mut account_info.data.borrow_mut()[..], self).ok()
|
||||
}
|
||||
fn get() -> Result<Self, ProgramError> {
|
||||
Err(ProgramError::UnsupportedSysvar)
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_sysvar_get {
|
||||
($syscall_name:ident) => {
|
||||
fn get() -> Result<Self, ProgramError> {
|
||||
let mut var = Self::default();
|
||||
let var_addr = &mut var as *mut _ as *mut u8;
|
||||
|
||||
#[cfg(target_arch = "bpf")]
|
||||
let result = unsafe {
|
||||
extern "C" {
|
||||
fn $syscall_name(var_addr: *mut u8) -> u64;
|
||||
}
|
||||
$syscall_name(var_addr)
|
||||
};
|
||||
#[cfg(not(target_arch = "bpf"))]
|
||||
let result = crate::program_stubs::$syscall_name(var_addr);
|
||||
|
||||
match result {
|
||||
crate::entrypoint::SUCCESS => Ok(var),
|
||||
e => Err(e.into()),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -2,8 +2,10 @@
|
||||
//!
|
||||
pub use crate::rent::Rent;
|
||||
|
||||
use crate::sysvar::Sysvar;
|
||||
use crate::{impl_sysvar_get, program_error::ProgramError, sysvar::Sysvar};
|
||||
|
||||
crate::declare_sysvar_id!("SysvarRent111111111111111111111111111111111", Rent);
|
||||
|
||||
impl Sysvar for Rent {}
|
||||
impl Sysvar for Rent {
|
||||
impl_sysvar_get!(sol_get_rent_sysvar);
|
||||
}
|
||||
|
@ -127,6 +127,10 @@ pub mod demote_sysvar_write_locks {
|
||||
solana_sdk::declare_id!("86LJYRuq2zgtHuL3FccR6hqFJQMQkFoun4knAxcPiF1P");
|
||||
}
|
||||
|
||||
pub mod sysvar_via_syscall {
|
||||
solana_sdk::declare_id!("7411E6gFQLDhQkdRjmpXwM1hzHMMoYQUjHicmvGPC1Nf");
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// Map of feature identifiers to user-visible description
|
||||
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
||||
@ -159,6 +163,7 @@ lazy_static! {
|
||||
(cpi_data_cost::id(), "charge the compute budget for data passed via CPI"),
|
||||
(upgradeable_close_instruction::id(), "close upgradeable buffer accounts"),
|
||||
(demote_sysvar_write_locks::id(), "demote builtins and sysvar write locks to readonly #15497"),
|
||||
(sysvar_via_syscall::id(), "Provide sysvars via syscalls"),
|
||||
/*************** ADD NEW FEATURES HERE ***************/
|
||||
]
|
||||
.iter()
|
||||
|
@ -7,7 +7,7 @@ use solana_sdk::{
|
||||
};
|
||||
use std::{cell::RefCell, fmt::Debug, rc::Rc, sync::Arc};
|
||||
|
||||
// Prototype of a native loader entry point
|
||||
/// Prototype of a native loader entry point
|
||||
///
|
||||
/// program_id: Program ID of the currently executing program
|
||||
/// keyed_accounts: Accounts passed as part of the instruction
|
||||
@ -68,6 +68,8 @@ pub trait InvokeContext {
|
||||
execute_us: u64,
|
||||
deserialize_us: u64,
|
||||
);
|
||||
/// Get sysvar data
|
||||
fn get_sysvar_data(&mut self, id: &Pubkey) -> Option<Rc<Vec<u8>>>;
|
||||
}
|
||||
|
||||
/// Convenience macro to log a message with an `Rc<RefCell<dyn Logger>>`
|
||||
@ -130,6 +132,8 @@ pub struct BpfComputeBudget {
|
||||
pub max_cpi_instruction_size: usize,
|
||||
/// Number of account data bytes per conpute unit charged during a cross-program invocation
|
||||
pub cpi_bytes_per_unit: u64,
|
||||
/// Base number of compute units consumed to get a sysvar
|
||||
pub sysvar_base_cost: u64,
|
||||
}
|
||||
impl Default for BpfComputeBudget {
|
||||
fn default() -> Self {
|
||||
@ -152,6 +156,7 @@ impl BpfComputeBudget {
|
||||
log_pubkey_units: 100,
|
||||
max_cpi_instruction_size: 1280, // IPv6 Min MTU size
|
||||
cpi_bytes_per_unit: 250, // ~50MB at 200,000 units
|
||||
sysvar_base_cost: 100,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -277,7 +282,9 @@ pub struct MockInvokeContext {
|
||||
pub bpf_compute_budget: BpfComputeBudget,
|
||||
pub compute_meter: MockComputeMeter,
|
||||
pub programs: Vec<(Pubkey, ProcessInstructionWithContext)>,
|
||||
pub accounts: Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>,
|
||||
pub invoke_depth: usize,
|
||||
pub sysvars: Vec<(Pubkey, Option<Rc<Vec<u8>>>)>,
|
||||
}
|
||||
impl Default for MockInvokeContext {
|
||||
fn default() -> Self {
|
||||
@ -289,7 +296,9 @@ impl Default for MockInvokeContext {
|
||||
remaining: std::i64::MAX as u64,
|
||||
},
|
||||
programs: vec![],
|
||||
accounts: vec![],
|
||||
invoke_depth: 0,
|
||||
sysvars: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -336,7 +345,12 @@ impl InvokeContext for MockInvokeContext {
|
||||
fn is_feature_active(&self, _feature_id: &Pubkey) -> bool {
|
||||
true
|
||||
}
|
||||
fn get_account(&self, _pubkey: &Pubkey) -> Option<Rc<RefCell<AccountSharedData>>> {
|
||||
fn get_account(&self, pubkey: &Pubkey) -> Option<Rc<RefCell<AccountSharedData>>> {
|
||||
for (key, account) in self.accounts.iter() {
|
||||
if key == pubkey {
|
||||
return Some(account.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
fn update_timing(
|
||||
@ -347,4 +361,9 @@ impl InvokeContext for MockInvokeContext {
|
||||
_deserialize_us: u64,
|
||||
) {
|
||||
}
|
||||
fn get_sysvar_data(&mut self, id: &Pubkey) -> Option<Rc<Vec<u8>>> {
|
||||
self.sysvars
|
||||
.iter()
|
||||
.find_map(|(key, sysvar)| if id == key { sysvar.clone() } else { None })
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user