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