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 check_aligned: bool,
10 memory_mapping: &mut MemoryMapping,
11 invoke_context: &mut InvokeContext,
12) -> Result<u64, Error> {
13 consume_compute_meter(
14 invoke_context,
15 invoke_context
16 .get_execution_cost()
17 .sysvar_base_cost
18 .saturating_add(size_of::<T>() as u64),
19 )?;
20
21 if var_addr >= ebpf::MM_INPUT_START
22 && invoke_context
23 .get_feature_set()
24 .stricter_abi_and_runtime_constraints
25 {
26 return Err(SyscallError::InvalidPointer.into());
27 }
28 translate_mut!(
29 memory_mapping,
30 check_aligned,
31 let var: &mut T = map(var_addr)?;
32 );
33
34 let sysvar: Arc<T> = sysvar?;
39 *var = T::clone(sysvar.as_ref());
40
41 Ok(SUCCESS)
42}
43
44declare_builtin_function!(
45 SyscallGetClockSysvar,
47 fn rust(
48 invoke_context: &mut InvokeContext,
49 var_addr: u64,
50 _arg2: u64,
51 _arg3: u64,
52 _arg4: u64,
53 _arg5: u64,
54 memory_mapping: &mut MemoryMapping,
55 ) -> Result<u64, Error> {
56 get_sysvar(
57 invoke_context.get_sysvar_cache().get_clock(),
58 var_addr,
59 invoke_context.get_check_aligned(),
60 memory_mapping,
61 invoke_context,
62 )
63 }
64);
65
66declare_builtin_function!(
67 SyscallGetEpochScheduleSysvar,
69 fn rust(
70 invoke_context: &mut InvokeContext,
71 var_addr: u64,
72 _arg2: u64,
73 _arg3: u64,
74 _arg4: u64,
75 _arg5: u64,
76 memory_mapping: &mut MemoryMapping,
77 ) -> Result<u64, Error> {
78 get_sysvar(
79 invoke_context.get_sysvar_cache().get_epoch_schedule(),
80 var_addr,
81 invoke_context.get_check_aligned(),
82 memory_mapping,
83 invoke_context,
84 )
85 }
86);
87
88declare_builtin_function!(
89 SyscallGetEpochRewardsSysvar,
91 fn rust(
92 invoke_context: &mut InvokeContext,
93 var_addr: u64,
94 _arg2: u64,
95 _arg3: u64,
96 _arg4: u64,
97 _arg5: u64,
98 memory_mapping: &mut MemoryMapping,
99 ) -> Result<u64, Error> {
100 get_sysvar(
101 invoke_context.get_sysvar_cache().get_epoch_rewards(),
102 var_addr,
103 invoke_context.get_check_aligned(),
104 memory_mapping,
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 memory_mapping: &mut MemoryMapping,
121 ) -> Result<u64, Error> {
122 #[allow(deprecated)]
123 {
124 get_sysvar(
125 invoke_context.get_sysvar_cache().get_fees(),
126 var_addr,
127 invoke_context.get_check_aligned(),
128 memory_mapping,
129 invoke_context,
130 )
131 }
132 }
133);
134
135declare_builtin_function!(
136 SyscallGetRentSysvar,
138 fn rust(
139 invoke_context: &mut InvokeContext,
140 var_addr: u64,
141 _arg2: u64,
142 _arg3: u64,
143 _arg4: u64,
144 _arg5: u64,
145 memory_mapping: &mut MemoryMapping,
146 ) -> Result<u64, Error> {
147 get_sysvar(
148 invoke_context.get_sysvar_cache().get_rent(),
149 var_addr,
150 invoke_context.get_check_aligned(),
151 memory_mapping,
152 invoke_context,
153 )
154 }
155);
156
157declare_builtin_function!(
158 SyscallGetLastRestartSlotSysvar,
160 fn rust(
161 invoke_context: &mut InvokeContext,
162 var_addr: u64,
163 _arg2: u64,
164 _arg3: u64,
165 _arg4: u64,
166 _arg5: u64,
167 memory_mapping: &mut MemoryMapping,
168 ) -> Result<u64, Error> {
169 get_sysvar(
170 invoke_context.get_sysvar_cache().get_last_restart_slot(),
171 var_addr,
172 invoke_context.get_check_aligned(),
173 memory_mapping,
174 invoke_context,
175 )
176 }
177);
178
179const SYSVAR_NOT_FOUND: u64 = 2;
180const OFFSET_LENGTH_EXCEEDS_SYSVAR: u64 = 1;
181
182declare_builtin_function!(
185 SyscallGetSysvar,
187 fn rust(
188 invoke_context: &mut InvokeContext,
189 sysvar_id_addr: u64,
190 var_addr: u64,
191 offset: u64,
192 length: u64,
193 _arg5: u64,
194 memory_mapping: &mut MemoryMapping,
195 ) -> Result<u64, Error> {
196 let check_aligned = invoke_context.get_check_aligned();
197 let SVMTransactionExecutionCost {
198 sysvar_base_cost,
199 cpi_bytes_per_unit,
200 mem_op_base_cost,
201 ..
202 } = *invoke_context.get_execution_cost();
203
204 let sysvar_id_cost = 32_u64.checked_div(cpi_bytes_per_unit).unwrap_or(0);
206 let sysvar_buf_cost = length.checked_div(cpi_bytes_per_unit).unwrap_or(0);
207 consume_compute_meter(
208 invoke_context,
209 sysvar_base_cost
210 .saturating_add(sysvar_id_cost)
211 .saturating_add(std::cmp::max(sysvar_buf_cost, mem_op_base_cost)),
212 )?;
213
214 if var_addr >= ebpf::MM_INPUT_START
215 && invoke_context
216 .get_feature_set()
217 .stricter_abi_and_runtime_constraints
218 {
219 return Err(SyscallError::InvalidPointer.into());
220 }
221 translate_mut!(
223 memory_mapping,
224 check_aligned,
225 let var: &mut [u8] = map(var_addr, length)?;
226 );
227
228 let sysvar_id = translate_type::<Pubkey>(memory_mapping, sysvar_id_addr, check_aligned)?;
230
231 let offset_length = offset
233 .checked_add(length)
234 .ok_or(InstructionError::ArithmeticOverflow)?;
235
236 let _ = var_addr
238 .checked_add(length)
239 .ok_or(InstructionError::ArithmeticOverflow)?;
240
241 let cache = invoke_context.get_sysvar_cache();
242
243 let Some(ref sysvar_buf) = cache.sysvar_id_to_buffer(sysvar_id) else { return Ok(SYSVAR_NOT_FOUND) };
245
246 if let Some(sysvar_slice) = sysvar_buf.get(offset as usize..offset_length as usize) {
248 var.copy_from_slice(sysvar_slice);
249 } else {
250 return Ok(OFFSET_LENGTH_EXCEEDS_SYSVAR);
251 }
252
253 Ok(SUCCESS)
254 }
255);