1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
2#![cfg_attr(feature = "frozen-abi", feature(min_specialization))]
3pub mod __private {
82 #[cfg(target_os = "solana")]
83 pub use solana_define_syscall::definitions;
84 pub use {solana_program_entrypoint::SUCCESS, solana_program_error::ProgramError};
85}
86use solana_pubkey::Pubkey;
87#[allow(deprecated)]
88#[doc(inline)]
89#[deprecated(
90 since = "2.0.0",
91 note = "please use `solana_sdk::reserved_account_keys::ReservedAccountKeys` instead"
92)]
93pub use sysvar_ids::ALL_IDS;
94#[cfg(feature = "bincode")]
95use {
96 solana_account_info::AccountInfo, solana_program_error::ProgramError,
97 solana_sysvar_id::SysvarId,
98};
99
100pub mod clock;
101pub mod epoch_rewards;
102pub mod epoch_schedule;
103pub mod fees;
104pub mod last_restart_slot;
105pub mod program_stubs;
106pub mod recent_blockhashes;
107pub mod rent;
108pub mod rewards;
109pub mod slot_hashes;
110pub mod slot_history;
111pub mod stake_history;
112
113#[deprecated(
114 since = "2.0.0",
115 note = "please use `solana_sdk::reserved_account_keys::ReservedAccountKeys` instead"
116)]
117mod sysvar_ids {
118 use {super::*, lazy_static::lazy_static};
119 lazy_static! {
120 pub static ref ALL_IDS: Vec<Pubkey> = vec![
122 clock::id(),
123 epoch_schedule::id(),
124 #[allow(deprecated)]
125 fees::id(),
126 #[allow(deprecated)]
127 recent_blockhashes::id(),
128 rent::id(),
129 rewards::id(),
130 slot_hashes::id(),
131 slot_history::id(),
132 stake_history::id(),
133 solana_sdk_ids::sysvar::instructions::id(),
134 ];
135 }
136}
137
138#[deprecated(
140 since = "2.0.0",
141 note = "please check the account's owner or use solana_sdk::reserved_account_keys::ReservedAccountKeys instead"
142)]
143#[allow(deprecated)]
144pub fn is_sysvar_id(id: &Pubkey) -> bool {
145 ALL_IDS.iter().any(|key| key == id)
146}
147
148#[cfg(feature = "bincode")]
149pub trait Sysvar:
151 SysvarId + Default + Sized + serde::Serialize + serde::de::DeserializeOwned
152{
153 fn size_of() -> usize {
155 bincode::serialized_size(&Self::default()).unwrap() as usize
156 }
157
158 fn from_account_info(account_info: &AccountInfo) -> Result<Self, ProgramError> {
165 if !Self::check_id(account_info.unsigned_key()) {
166 return Err(ProgramError::InvalidArgument);
167 }
168 bincode::deserialize(&account_info.data.borrow()).map_err(|_| ProgramError::InvalidArgument)
169 }
170
171 fn to_account_info(&self, account_info: &mut AccountInfo) -> Option<()> {
177 bincode::serialize_into(&mut account_info.data.borrow_mut()[..], self).ok()
178 }
179
180 fn get() -> Result<Self, ProgramError> {
189 Err(ProgramError::UnsupportedSysvar)
190 }
191}
192
193#[macro_export]
195macro_rules! impl_sysvar_get {
196 ($syscall_name:ident) => {
197 fn get() -> Result<Self, $crate::__private::ProgramError> {
198 let mut var = Self::default();
199 let var_addr = &mut var as *mut _ as *mut u8;
200
201 #[cfg(target_os = "solana")]
202 let result = unsafe { $crate::__private::definitions::$syscall_name(var_addr) };
203
204 #[cfg(not(target_os = "solana"))]
205 let result = $crate::program_stubs::$syscall_name(var_addr);
206
207 match result {
208 $crate::__private::SUCCESS => Ok(var),
209 e => Err(e.into()),
210 }
211 }
212 };
213}
214
215fn get_sysvar(
218 dst: &mut [u8],
219 sysvar_id: &Pubkey,
220 offset: u64,
221 length: u64,
222) -> Result<(), solana_program_error::ProgramError> {
223 if dst.len() < length as usize {
226 return Err(solana_program_error::ProgramError::InvalidArgument);
227 }
228
229 let sysvar_id = sysvar_id as *const _ as *const u8;
230 let var_addr = dst as *mut _ as *mut u8;
231
232 #[cfg(target_os = "solana")]
233 let result = unsafe {
234 solana_define_syscall::definitions::sol_get_sysvar(sysvar_id, var_addr, offset, length)
235 };
236
237 #[cfg(not(target_os = "solana"))]
238 let result = crate::program_stubs::sol_get_sysvar(sysvar_id, var_addr, offset, length);
239
240 match result {
241 solana_program_entrypoint::SUCCESS => Ok(()),
242 e => Err(e.into()),
243 }
244}
245
246#[cfg(test)]
247mod tests {
248 use {
249 super::*,
250 crate::program_stubs::{set_syscall_stubs, SyscallStubs},
251 serde_derive::{Deserialize, Serialize},
252 solana_clock::Epoch,
253 solana_program_entrypoint::SUCCESS,
254 solana_program_error::ProgramError,
255 solana_pubkey::Pubkey,
256 std::{cell::RefCell, rc::Rc},
257 };
258
259 #[repr(C)]
260 #[derive(Serialize, Deserialize, Debug, Default, PartialEq, Eq)]
261 struct TestSysvar {
262 something: Pubkey,
263 }
264 solana_pubkey::declare_id!("TestSysvar111111111111111111111111111111111");
265 impl solana_sysvar_id::SysvarId for TestSysvar {
266 fn id() -> solana_pubkey::Pubkey {
267 id()
268 }
269
270 fn check_id(pubkey: &solana_pubkey::Pubkey) -> bool {
271 check_id(pubkey)
272 }
273 }
274 impl Sysvar for TestSysvar {}
275
276 struct MockGetSysvarSyscall {
278 data: Vec<u8>,
279 }
280 impl SyscallStubs for MockGetSysvarSyscall {
281 #[allow(clippy::arithmetic_side_effects)]
282 fn sol_get_sysvar(
283 &self,
284 _sysvar_id_addr: *const u8,
285 var_addr: *mut u8,
286 offset: u64,
287 length: u64,
288 ) -> u64 {
289 let slice = unsafe { std::slice::from_raw_parts_mut(var_addr, length as usize) };
290 slice.copy_from_slice(&self.data[offset as usize..(offset + length) as usize]);
291 SUCCESS
292 }
293 }
294 pub fn mock_get_sysvar_syscall(data: &[u8]) {
295 set_syscall_stubs(Box::new(MockGetSysvarSyscall {
296 data: data.to_vec(),
297 }));
298 }
299
300 #[test]
301 fn test_sysvar_account_info_to_from() {
302 let test_sysvar = TestSysvar::default();
303 let key = id();
304 let wrong_key = Pubkey::new_unique();
305 let owner = Pubkey::new_unique();
306 let mut lamports = 42;
307 let mut data = vec![0_u8; TestSysvar::size_of()];
308 let mut account_info = AccountInfo::new(
309 &key,
310 false,
311 true,
312 &mut lamports,
313 &mut data,
314 &owner,
315 false,
316 Epoch::default(),
317 );
318
319 test_sysvar.to_account_info(&mut account_info).unwrap();
320 let new_test_sysvar = TestSysvar::from_account_info(&account_info).unwrap();
321 assert_eq!(test_sysvar, new_test_sysvar);
322
323 account_info.key = &wrong_key;
324 assert_eq!(
325 TestSysvar::from_account_info(&account_info),
326 Err(ProgramError::InvalidArgument)
327 );
328
329 let mut small_data = vec![];
330 account_info.data = Rc::new(RefCell::new(&mut small_data));
331 assert_eq!(test_sysvar.to_account_info(&mut account_info), None);
332 }
333}