hbros_solana_program/sysvar/
mod.rs1use crate::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey};
85#[allow(deprecated)]
86pub use sysvar_ids::ALL_IDS;
87
88pub mod clock;
89pub mod epoch_rewards;
90pub mod epoch_schedule;
91pub mod fees;
92pub mod instructions;
93pub mod last_restart_slot;
94pub mod recent_blockhashes;
95pub mod rent;
96pub mod rewards;
97pub mod slot_hashes;
98pub mod slot_history;
99pub mod stake_history;
100
101#[deprecated(
102 since = "2.0.0",
103 note = "please use `solana_sdk::reserved_account_keys::ReservedAccountKeys` instead"
104)]
105mod sysvar_ids {
106 use {super::*, lazy_static::lazy_static};
107 lazy_static! {
108 pub static ref ALL_IDS: Vec<Pubkey> = vec![
110 clock::id(),
111 epoch_schedule::id(),
112 #[allow(deprecated)]
113 fees::id(),
114 #[allow(deprecated)]
115 recent_blockhashes::id(),
116 rent::id(),
117 rewards::id(),
118 slot_hashes::id(),
119 slot_history::id(),
120 stake_history::id(),
121 instructions::id(),
122 ];
123 }
124}
125
126#[deprecated(
128 since = "2.0.0",
129 note = "please check the account's owner or use solana_sdk::reserved_account_keys::ReservedAccountKeys instead"
130)]
131#[allow(deprecated)]
132pub fn is_sysvar_id(id: &Pubkey) -> bool {
133 ALL_IDS.iter().any(|key| key == id)
134}
135
136#[macro_export]
138macro_rules! declare_sysvar_id(
139 ($name:expr, $type:ty) => (
140 $crate::declare_id!($name);
141
142 impl $crate::sysvar::SysvarId for $type {
143 fn id() -> $crate::pubkey::Pubkey {
144 id()
145 }
146
147 fn check_id(pubkey: &$crate::pubkey::Pubkey) -> bool {
148 check_id(pubkey)
149 }
150 }
151 )
152);
153
154#[macro_export]
156macro_rules! declare_deprecated_sysvar_id(
157 ($name:expr, $type:ty) => (
158 $crate::declare_deprecated_id!($name);
159
160 impl $crate::sysvar::SysvarId for $type {
161 fn id() -> $crate::pubkey::Pubkey {
162 #[allow(deprecated)]
163 id()
164 }
165
166 fn check_id(pubkey: &$crate::pubkey::Pubkey) -> bool {
167 #[allow(deprecated)]
168 check_id(pubkey)
169 }
170 }
171 )
172);
173
174crate::declare_id!("Sysvar1111111111111111111111111111111111111");
176
177pub trait SysvarId {
179 fn id() -> Pubkey;
181
182 fn check_id(pubkey: &Pubkey) -> bool;
184}
185
186pub trait Sysvar:
188 SysvarId + Default + Sized + serde::Serialize + serde::de::DeserializeOwned
189{
190 fn size_of() -> usize {
192 bincode::serialized_size(&Self::default()).unwrap() as usize
193 }
194
195 fn from_account_info(account_info: &AccountInfo) -> Result<Self, ProgramError> {
202 if !Self::check_id(account_info.unsigned_key()) {
203 return Err(ProgramError::InvalidArgument);
204 }
205 bincode::deserialize(&account_info.data.borrow()).map_err(|_| ProgramError::InvalidArgument)
206 }
207
208 fn to_account_info(&self, account_info: &mut AccountInfo) -> Option<()> {
214 bincode::serialize_into(&mut account_info.data.borrow_mut()[..], self).ok()
215 }
216
217 fn get() -> Result<Self, ProgramError> {
226 Err(ProgramError::UnsupportedSysvar)
227 }
228}
229
230#[macro_export]
232macro_rules! impl_sysvar_get {
233 ($syscall_name:ident) => {
234 fn get() -> Result<Self, ProgramError> {
235 let mut var = Self::default();
236 let var_addr = &mut var as *mut _ as *mut u8;
237
238 #[cfg(target_os = "solana")]
239 let result = unsafe { $crate::syscalls::$syscall_name(var_addr) };
240
241 #[cfg(not(target_os = "solana"))]
242 let result = $crate::program_stubs::$syscall_name(var_addr);
243
244 match result {
245 $crate::entrypoint::SUCCESS => Ok(var),
246 e => Err(e.into()),
247 }
248 }
249 };
250}
251
252fn get_sysvar(
255 dst: &mut [u8],
256 sysvar_id: &Pubkey,
257 offset: u64,
258 length: u64,
259) -> Result<(), ProgramError> {
260 if dst.len() < length as usize {
263 return Err(ProgramError::InvalidArgument);
264 }
265
266 let sysvar_id = sysvar_id as *const _ as *const u8;
267 let var_addr = dst as *mut _ as *mut u8;
268
269 #[cfg(target_os = "solana")]
270 let result = unsafe { crate::syscalls::sol_get_sysvar(sysvar_id, var_addr, offset, length) };
271
272 #[cfg(not(target_os = "solana"))]
273 let result = crate::program_stubs::sol_get_sysvar(sysvar_id, var_addr, offset, length);
274
275 match result {
276 crate::entrypoint::SUCCESS => Ok(()),
277 e => Err(e.into()),
278 }
279}
280
281#[cfg(test)]
282mod tests {
283 use {
284 super::*,
285 crate::{
286 entrypoint::SUCCESS,
287 program_error::ProgramError,
288 program_stubs::{set_syscall_stubs, SyscallStubs},
289 pubkey::Pubkey,
290 },
291 solana_clock::Epoch,
292 std::{cell::RefCell, rc::Rc},
293 };
294
295 #[repr(C)]
296 #[derive(Serialize, Deserialize, Debug, Default, PartialEq, Eq)]
297 struct TestSysvar {
298 something: Pubkey,
299 }
300 crate::declare_id!("TestSysvar111111111111111111111111111111111");
301 impl crate::sysvar::SysvarId for TestSysvar {
302 fn id() -> crate::pubkey::Pubkey {
303 id()
304 }
305
306 fn check_id(pubkey: &crate::pubkey::Pubkey) -> bool {
307 check_id(pubkey)
308 }
309 }
310 impl Sysvar for TestSysvar {}
311
312 struct MockGetSysvarSyscall {
314 data: Vec<u8>,
315 }
316 impl SyscallStubs for MockGetSysvarSyscall {
317 #[allow(clippy::arithmetic_side_effects)]
318 fn sol_get_sysvar(
319 &self,
320 _sysvar_id_addr: *const u8,
321 var_addr: *mut u8,
322 offset: u64,
323 length: u64,
324 ) -> u64 {
325 let slice = unsafe { std::slice::from_raw_parts_mut(var_addr, length as usize) };
326 slice.copy_from_slice(&self.data[offset as usize..(offset + length) as usize]);
327 SUCCESS
328 }
329 }
330 pub fn mock_get_sysvar_syscall(data: &[u8]) {
331 set_syscall_stubs(Box::new(MockGetSysvarSyscall {
332 data: data.to_vec(),
333 }));
334 }
335
336 #[test]
337 fn test_sysvar_account_info_to_from() {
338 let test_sysvar = TestSysvar::default();
339 let key = crate::sysvar::tests::id();
340 let wrong_key = Pubkey::new_unique();
341 let owner = Pubkey::new_unique();
342 let mut lamports = 42;
343 let mut data = vec![0_u8; TestSysvar::size_of()];
344 let mut account_info = AccountInfo::new(
345 &key,
346 false,
347 true,
348 &mut lamports,
349 &mut data,
350 &owner,
351 false,
352 Epoch::default(),
353 );
354
355 test_sysvar.to_account_info(&mut account_info).unwrap();
356 let new_test_sysvar = TestSysvar::from_account_info(&account_info).unwrap();
357 assert_eq!(test_sysvar, new_test_sysvar);
358
359 account_info.key = &wrong_key;
360 assert_eq!(
361 TestSysvar::from_account_info(&account_info),
362 Err(ProgramError::InvalidArgument)
363 );
364
365 let mut small_data = vec![];
366 account_info.data = Rc::new(RefCell::new(&mut small_data));
367 assert_eq!(test_sysvar.to_account_info(&mut account_info), None);
368 }
369}