1use {
2 super::*, crate::translate_mut,
3 solana_program_runtime::execution_budget::SVMTransactionExecutionCost, solana_sbpf::ebpf,
4};
5
6fn get_sysvar<T: std::fmt::Debug + SysvarSerialize + Clone>(
7 sysvar: Result<Arc<T>, InstructionError>,
8 var_addr: u64,
9 invoke_context: &mut InvokeContext,
10) -> Result<u64, Error> {
11 let amount = invoke_context
12 .get_execution_cost()
13 .sysvar_base_cost
14 .saturating_add(size_of::<T>() as u64);
15 invoke_context.compute_meter.consume_checked(amount)?;
16
17 let check_aligned = invoke_context.get_check_aligned();
23 if !check_aligned {
24 return Err(SyscallError::UnalignedPointer.into());
25 }
26
27 if var_addr >= ebpf::MM_INPUT_START
28 && invoke_context
29 .get_feature_set()
30 .syscall_parameter_address_restrictions
31 {
32 return Err(SyscallError::InvalidPointer.into());
33 }
34
35 let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
36 translate_mut!(
37 memory_mapping,
38 check_aligned,
39 let var: (&mut std::mem::MaybeUninit<T>) = map(var_addr)?;
40 );
41
42 let sysvar: Arc<T> = sysvar?;
47 var.write(T::clone(&sysvar));
48
49 Ok(SUCCESS)
50}
51
52declare_builtin_function!(
53 SyscallGetClockSysvar,
55 fn rust(
56 invoke_context: &mut InvokeContext<'_, '_>,
57 var_addr: u64,
58 _arg2: u64,
59 _arg3: u64,
60 _arg4: u64,
61 _arg5: u64,
62 ) -> Result<u64, Error> {
63 get_sysvar(
64 invoke_context.environment_config.sysvar_cache().get_clock(),
65 var_addr,
66 invoke_context,
67 )
68 }
69);
70
71declare_builtin_function!(
72 SyscallGetEpochScheduleSysvar,
74 fn rust(
75 invoke_context: &mut InvokeContext<'_, '_>,
76 var_addr: u64,
77 _arg2: u64,
78 _arg3: u64,
79 _arg4: u64,
80 _arg5: u64,
81 ) -> Result<u64, Error> {
82 get_sysvar(
83 invoke_context.environment_config.sysvar_cache().get_epoch_schedule(),
84 var_addr,
85 invoke_context,
86 )
87 }
88);
89
90declare_builtin_function!(
91 SyscallGetEpochRewardsSysvar,
93 fn rust(
94 invoke_context: &mut InvokeContext<'_, '_>,
95 var_addr: u64,
96 _arg2: u64,
97 _arg3: u64,
98 _arg4: u64,
99 _arg5: u64,
100 ) -> Result<u64, Error> {
101 get_sysvar(
102 invoke_context.environment_config.sysvar_cache().get_epoch_rewards(),
103 var_addr,
104 invoke_context,
105 )
106 }
107);
108
109declare_builtin_function!(
110 SyscallGetFeesSysvar,
112 fn rust(
113 invoke_context: &mut InvokeContext<'_, '_>,
114 var_addr: u64,
115 _arg2: u64,
116 _arg3: u64,
117 _arg4: u64,
118 _arg5: u64,
119 ) -> Result<u64, Error> {
120 #[expect(deprecated)]
121 {
122 get_sysvar(
123 invoke_context.environment_config.sysvar_cache().get_fees(),
124 var_addr,
125 invoke_context,
126 )
127 }
128 }
129);
130
131declare_builtin_function!(
132 SyscallGetRentSysvar,
134 fn rust(
135 invoke_context: &mut InvokeContext<'_, '_>,
136 var_addr: u64,
137 _arg2: u64,
138 _arg3: u64,
139 _arg4: u64,
140 _arg5: u64,
141 ) -> Result<u64, Error> {
142 get_sysvar(
143 invoke_context.environment_config.sysvar_cache().get_rent(),
144 var_addr,
145 invoke_context,
146 )
147 }
148);
149
150declare_builtin_function!(
151 SyscallGetLastRestartSlotSysvar,
153 fn rust(
154 invoke_context: &mut InvokeContext<'_, '_>,
155 var_addr: u64,
156 _arg2: u64,
157 _arg3: u64,
158 _arg4: u64,
159 _arg5: u64,
160 ) -> Result<u64, Error> {
161 get_sysvar(
162 invoke_context.environment_config.sysvar_cache().get_last_restart_slot(),
163 var_addr,
164 invoke_context,
165 )
166 }
167);
168
169const SYSVAR_NOT_FOUND: u64 = 2;
170const OFFSET_LENGTH_EXCEEDS_SYSVAR: u64 = 1;
171
172declare_builtin_function!(
175 SyscallGetSysvar,
177 fn rust(
178 invoke_context: &mut InvokeContext<'_, '_>,
179 sysvar_id_addr: u64,
180 var_addr: u64,
181 offset: u64,
182 length: u64,
183 _arg5: u64,
184 ) -> Result<u64, Error> {
185 let SVMTransactionExecutionCost {
186 sysvar_base_cost,
187 cpi_bytes_per_unit,
188 mem_op_base_cost,
189 ..
190 } = *invoke_context.get_execution_cost();
191
192 let sysvar_id_cost = 32_u64.checked_div(cpi_bytes_per_unit).unwrap_or(0);
194 let sysvar_buf_cost = length.checked_div(cpi_bytes_per_unit).unwrap_or(0);
195 let cost = sysvar_base_cost
196 .saturating_add(sysvar_id_cost)
197 .saturating_add(std::cmp::max(sysvar_buf_cost, mem_op_base_cost));
198 invoke_context.compute_meter.consume_checked(cost)?;
199
200 let check_aligned = invoke_context.get_check_aligned();
206 if !check_aligned {
207 return Err(SyscallError::UnalignedPointer.into());
208 }
209
210 if var_addr >= ebpf::MM_INPUT_START
211 && invoke_context
212 .get_feature_set()
213 .syscall_parameter_address_restrictions
214 {
215 return Err(SyscallError::InvalidPointer.into());
216 }
217
218 let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
219 translate_mut!(
221 memory_mapping,
222 check_aligned,
223 let var: (&mut [MaybeUninit<u8>]) = map(var_addr, length)?;
224 );
225
226 let sysvar_id = translate_type::<Pubkey>(memory_mapping, sysvar_id_addr, check_aligned)?;
228
229 let offset_length = offset
231 .checked_add(length)
232 .ok_or(InstructionError::ArithmeticOverflow)?;
233
234 let _ = var_addr
236 .checked_add(length)
237 .ok_or(InstructionError::ArithmeticOverflow)?;
238
239
240 let cache = invoke_context.environment_config.sysvar_cache();
242 let Some(sysvar_buf) = cache.sysvar_id_to_buffer(sysvar_id) else {
243 return Ok(SYSVAR_NOT_FOUND)
244 };
245
246 if let Some(sysvar_slice) = sysvar_buf.get(offset as usize..offset_length as usize) {
248 var.write_copy_of_slice(sysvar_slice);
249 } else {
250 return Ok(OFFSET_LENGTH_EXCEEDS_SYSVAR);
251 }
252
253 Ok(SUCCESS)
254 }
255);