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 return Err(SyscallError::InvalidPointer.into());
30 }
31
32 let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
33 translate_mut!(
34 memory_mapping,
35 check_aligned,
36 let var: (&mut std::mem::MaybeUninit<T>) = map(var_addr)?;
37 );
38
39 let sysvar: Arc<T> = sysvar?;
44 var.write(T::clone(&sysvar));
45
46 Ok(SUCCESS)
47}
48
49pub struct SyscallGetClockSysvar {}
51impl BuiltinFunctionDefinition<InvokeContext<'_, '_>> for SyscallGetClockSysvar {
52 type Error = Error;
53
54 fn rust(
55 invoke_context: &mut InvokeContext<'_, '_>,
56 var_addr: u64,
57 _arg2: u64,
58 _arg3: u64,
59 _arg4: u64,
60 _arg5: u64,
61 ) -> Result<u64, Error> {
62 get_sysvar(
63 invoke_context.environment_config.sysvar_cache().get_clock(),
64 var_addr,
65 invoke_context,
66 )
67 }
68}
69
70pub struct SyscallGetEpochScheduleSysvar {}
72impl BuiltinFunctionDefinition<InvokeContext<'_, '_>> for SyscallGetEpochScheduleSysvar {
73 type Error = Error;
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
84 .environment_config
85 .sysvar_cache()
86 .get_epoch_schedule(),
87 var_addr,
88 invoke_context,
89 )
90 }
91}
92
93pub struct SyscallGetEpochRewardsSysvar {}
95impl BuiltinFunctionDefinition<InvokeContext<'_, '_>> for SyscallGetEpochRewardsSysvar {
96 type Error = Error;
97 fn rust(
98 invoke_context: &mut InvokeContext<'_, '_>,
99 var_addr: u64,
100 _arg2: u64,
101 _arg3: u64,
102 _arg4: u64,
103 _arg5: u64,
104 ) -> Result<u64, Error> {
105 get_sysvar(
106 invoke_context
107 .environment_config
108 .sysvar_cache()
109 .get_epoch_rewards(),
110 var_addr,
111 invoke_context,
112 )
113 }
114}
115
116pub struct SyscallGetFeesSysvar {}
118impl BuiltinFunctionDefinition<InvokeContext<'_, '_>> for SyscallGetFeesSysvar {
119 type Error = Error;
120 fn rust(
121 invoke_context: &mut InvokeContext<'_, '_>,
122 var_addr: u64,
123 _arg2: u64,
124 _arg3: u64,
125 _arg4: u64,
126 _arg5: u64,
127 ) -> Result<u64, Error> {
128 #[expect(deprecated)]
129 {
130 get_sysvar(
131 invoke_context.environment_config.sysvar_cache().get_fees(),
132 var_addr,
133 invoke_context,
134 )
135 }
136 }
137}
138
139pub struct SyscallGetRentSysvar {}
141impl BuiltinFunctionDefinition<InvokeContext<'_, '_>> for SyscallGetRentSysvar {
142 type Error = Error;
143 fn rust(
144 invoke_context: &mut InvokeContext<'_, '_>,
145 var_addr: u64,
146 _arg2: u64,
147 _arg3: u64,
148 _arg4: u64,
149 _arg5: u64,
150 ) -> Result<u64, Error> {
151 get_sysvar(
152 invoke_context.environment_config.sysvar_cache().get_rent(),
153 var_addr,
154 invoke_context,
155 )
156 }
157}
158
159pub struct SyscallGetLastRestartSlotSysvar {}
161impl BuiltinFunctionDefinition<InvokeContext<'_, '_>> for SyscallGetLastRestartSlotSysvar {
162 type Error = Error;
163 fn rust(
164 invoke_context: &mut InvokeContext<'_, '_>,
165 var_addr: u64,
166 _arg2: u64,
167 _arg3: u64,
168 _arg4: u64,
169 _arg5: u64,
170 ) -> Result<u64, Error> {
171 get_sysvar(
172 invoke_context
173 .environment_config
174 .sysvar_cache()
175 .get_last_restart_slot(),
176 var_addr,
177 invoke_context,
178 )
179 }
180}
181
182const SYSVAR_NOT_FOUND: u64 = 2;
183const OFFSET_LENGTH_EXCEEDS_SYSVAR: u64 = 1;
184
185pub struct SyscallGetSysvar {}
189impl BuiltinFunctionDefinition<InvokeContext<'_, '_>> for SyscallGetSysvar {
190 type Error = Error;
191 fn rust(
192 invoke_context: &mut InvokeContext<'_, '_>,
193 sysvar_id_addr: u64,
194 var_addr: u64,
195 offset: u64,
196 length: u64,
197 _arg5: u64,
198 ) -> Result<u64, Error> {
199 let SVMTransactionExecutionCost {
200 sysvar_base_cost,
201 cpi_bytes_per_unit,
202 mem_op_base_cost,
203 ..
204 } = *invoke_context.get_execution_cost();
205
206 let sysvar_id_cost = 32_u64.checked_div(cpi_bytes_per_unit).unwrap_or(0);
208 let sysvar_buf_cost = length.checked_div(cpi_bytes_per_unit).unwrap_or(0);
209 let cost = sysvar_base_cost
210 .saturating_add(sysvar_id_cost)
211 .saturating_add(std::cmp::max(sysvar_buf_cost, mem_op_base_cost));
212 invoke_context.compute_meter.consume_checked(cost)?;
213
214 let check_aligned = invoke_context.get_check_aligned();
220 if !check_aligned {
221 return Err(SyscallError::UnalignedPointer.into());
222 }
223
224 if var_addr >= ebpf::MM_INPUT_START {
225 return Err(SyscallError::InvalidPointer.into());
226 }
227
228 let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
229 {
231 translate_mut!(
233 memory_mapping,
234 check_aligned,
235 let _var: (&mut [MaybeUninit<u8>]) = map(var_addr, length)?;
236 );
237 }
238
239 let sysvar_id = translate_type::<Pubkey>(memory_mapping, sysvar_id_addr, check_aligned)?;
241
242 let offset_length = offset
244 .checked_add(length)
245 .ok_or(InstructionError::ArithmeticOverflow)?;
246
247 let _ = var_addr
249 .checked_add(length)
250 .ok_or(InstructionError::ArithmeticOverflow)?;
251
252 let cache = invoke_context.environment_config.sysvar_cache();
254 let Some(sysvar_buf) = cache.sysvar_id_to_buffer(sysvar_id) else {
255 return Ok(SYSVAR_NOT_FOUND);
256 };
257
258 if let Some(sysvar_slice) = sysvar_buf.get(offset as usize..offset_length as usize) {
260 translate_mut!(
261 memory_mapping,
262 check_aligned,
263 let var: (&mut [MaybeUninit<u8>]) = map(var_addr, length)?;
264 );
265 var.write_copy_of_slice(sysvar_slice);
266 } else {
267 return Ok(OFFSET_LENGTH_EXCEEDS_SYSVAR);
268 }
269
270 Ok(SUCCESS)
271 }
272}