1use {
2 crate::config::{ExecutionCost, SysvarContext},
3 sbpf_vm::{compute::ComputeMeter, errors::SbpfVmResult, memory::Memory},
4 solana_clock::Clock,
5 solana_epoch_schedule::EpochSchedule,
6 solana_last_restart_slot::LastRestartSlot,
7 solana_rent::Rent,
8 std::mem::size_of,
9};
10
11fn write_sysvar_bytes<T>(memory: &mut Memory, addr: u64, sysvar: &T) -> SbpfVmResult<()> {
12 let bytes =
13 unsafe { std::slice::from_raw_parts(sysvar as *const T as *const u8, size_of::<T>()) };
14 memory.write_bytes(addr, bytes)
15}
16
17pub fn sol_get_clock_sysvar(
18 registers: [u64; 5],
19 memory: &mut Memory,
20 compute: &ComputeMeter,
21 costs: &ExecutionCost,
22 sysvars: &SysvarContext,
23) -> SbpfVmResult<u64> {
24 compute.consume(
25 costs
26 .sysvar_base_cost
27 .saturating_add(size_of::<Clock>() as u64),
28 )?;
29 write_sysvar_bytes(memory, registers[0], &sysvars.clock)?;
30 Ok(0)
31}
32
33pub fn sol_get_rent_sysvar(
34 registers: [u64; 5],
35 memory: &mut Memory,
36 compute: &ComputeMeter,
37 costs: &ExecutionCost,
38 sysvars: &SysvarContext,
39) -> SbpfVmResult<u64> {
40 compute.consume(
41 costs
42 .sysvar_base_cost
43 .saturating_add(size_of::<Rent>() as u64),
44 )?;
45 write_sysvar_bytes(memory, registers[0], &sysvars.rent)?;
46 Ok(0)
47}
48
49pub fn sol_get_epoch_schedule_sysvar(
50 registers: [u64; 5],
51 memory: &mut Memory,
52 compute: &ComputeMeter,
53 costs: &ExecutionCost,
54 sysvars: &SysvarContext,
55) -> SbpfVmResult<u64> {
56 compute.consume(
57 costs
58 .sysvar_base_cost
59 .saturating_add(size_of::<EpochSchedule>() as u64),
60 )?;
61 write_sysvar_bytes(memory, registers[0], &sysvars.epoch_schedule)?;
62 Ok(0)
63}
64
65pub fn sol_get_last_restart_slot_sysvar(
66 registers: [u64; 5],
67 memory: &mut Memory,
68 compute: &ComputeMeter,
69 costs: &ExecutionCost,
70 sysvars: &SysvarContext,
71) -> SbpfVmResult<u64> {
72 compute.consume(
73 costs
74 .sysvar_base_cost
75 .saturating_add(size_of::<LastRestartSlot>() as u64),
76 )?;
77 write_sysvar_bytes(memory, registers[0], &sysvars.last_restart_slot)?;
78 Ok(0)
79}
80
81#[cfg(test)]
82mod tests {
83 use {
84 super::*,
85 crate::{
86 config::SysvarContext,
87 syscalls::tests::test_helpers::{costs, make_memory, meter},
88 },
89 sbpf_vm::{errors::SbpfVmError, memory::Memory},
90 };
91
92 fn raw_bytes<T>(val: &T) -> Vec<u8> {
93 unsafe { std::slice::from_raw_parts(val as *const T as *const u8, size_of::<T>()).to_vec() }
94 }
95
96 #[test]
97 fn test_sol_get_clock_sysvar() {
98 let mut memory = make_memory();
99 let mut sysvars = SysvarContext::default();
100 sysvars.clock.slot = 99_999;
101 sysvars.clock.unix_timestamp = 1_700_000_000;
102
103 let addr = Memory::HEAP_START;
104 let registers = [addr, 0, 0, 0, 0];
105 sol_get_clock_sysvar(
106 registers,
107 &mut memory,
108 &meter(1_000_000),
109 &costs(),
110 &sysvars,
111 )
112 .unwrap();
113
114 let written = memory.read_bytes(addr, size_of::<Clock>()).unwrap();
115 assert_eq!(written, raw_bytes(&sysvars.clock).as_slice());
116 }
117
118 #[test]
119 fn test_sol_get_clock_sysvar_compute_exhausted() {
120 let mut memory = make_memory();
121 let sysvars = SysvarContext::default();
122 let cost = costs().sysvar_base_cost + size_of::<Clock>() as u64;
123 let registers = [Memory::HEAP_START, 0, 0, 0, 0];
124 assert!(matches!(
125 sol_get_clock_sysvar(registers, &mut memory, &meter(cost - 1), &costs(), &sysvars),
126 Err(SbpfVmError::ComputeBudgetExceeded { .. })
127 ));
128 }
129
130 #[test]
131 fn test_sol_get_rent_sysvar() {
132 let mut memory = make_memory();
133 let sysvars = SysvarContext {
134 rent: Rent::with_lamports_per_byte(3_480),
135 ..Default::default()
136 };
137
138 let addr = Memory::HEAP_START;
139 let registers = [addr, 0, 0, 0, 0];
140 sol_get_rent_sysvar(
141 registers,
142 &mut memory,
143 &meter(1_000_000),
144 &costs(),
145 &sysvars,
146 )
147 .unwrap();
148
149 let written = memory.read_bytes(addr, size_of::<Rent>()).unwrap();
150 assert_eq!(written, raw_bytes(&sysvars.rent).as_slice());
151 }
152
153 #[test]
154 fn test_sol_get_epoch_schedule_sysvar() {
155 let mut memory = make_memory();
156 let mut sysvars = SysvarContext::default();
157 sysvars.epoch_schedule.slots_per_epoch = 432_000;
158
159 let addr = Memory::HEAP_START;
160 let registers = [addr, 0, 0, 0, 0];
161 sol_get_epoch_schedule_sysvar(
162 registers,
163 &mut memory,
164 &meter(1_000_000),
165 &costs(),
166 &sysvars,
167 )
168 .unwrap();
169
170 let written = memory.read_bytes(addr, size_of::<EpochSchedule>()).unwrap();
171 assert_eq!(written, raw_bytes(&sysvars.epoch_schedule).as_slice());
172 }
173
174 #[test]
175 fn test_sol_get_last_restart_slot_sysvar() {
176 let mut memory = make_memory();
177 let mut sysvars = SysvarContext::default();
178 sysvars.last_restart_slot.last_restart_slot = 12_345_678;
179
180 let addr = Memory::HEAP_START;
181 let registers = [addr, 0, 0, 0, 0];
182 sol_get_last_restart_slot_sysvar(
183 registers,
184 &mut memory,
185 &meter(1_000_000),
186 &costs(),
187 &sysvars,
188 )
189 .unwrap();
190
191 let written = memory
192 .read_bytes(addr, size_of::<LastRestartSlot>())
193 .unwrap();
194 assert_eq!(written, raw_bytes(&sysvars.last_restart_slot).as_slice());
195 }
196}