1#[allow(deprecated)]
2use cbe_sdk::sysvar::{fees::Fees, recent_blockhashes::RecentBlockhashes};
3use {
4 crate::invoke_context::InvokeContext,
5 cbe_sdk::{
6 instruction::InstructionError,
7 pubkey::Pubkey,
8 sysvar::{
9 clock::Clock, epoch_schedule::EpochSchedule, rent::Rent, slot_hashes::SlotHashes,
10 stake_history::StakeHistory, Sysvar, SysvarId,
11 },
12 transaction_context::{IndexOfAccount, InstructionContext, TransactionContext},
13 },
14 std::sync::Arc,
15};
16
17#[cfg(RUSTC_WITH_SPECIALIZATION)]
18impl ::cbe_frozen_abi::abi_example::AbiExample for SysvarCache {
19 fn example() -> Self {
20 SysvarCache::default()
22 }
23}
24
25#[derive(Default, Clone, Debug)]
26pub struct SysvarCache {
27 clock: Option<Arc<Clock>>,
28 epoch_schedule: Option<Arc<EpochSchedule>>,
29 #[allow(deprecated)]
30 fees: Option<Arc<Fees>>,
31 rent: Option<Arc<Rent>>,
32 slot_hashes: Option<Arc<SlotHashes>>,
33 #[allow(deprecated)]
34 recent_blockhashes: Option<Arc<RecentBlockhashes>>,
35 stake_history: Option<Arc<StakeHistory>>,
36}
37
38impl SysvarCache {
39 pub fn get_clock(&self) -> Result<Arc<Clock>, InstructionError> {
40 self.clock
41 .clone()
42 .ok_or(InstructionError::UnsupportedSysvar)
43 }
44
45 pub fn set_clock(&mut self, clock: Clock) {
46 self.clock = Some(Arc::new(clock));
47 }
48
49 pub fn get_epoch_schedule(&self) -> Result<Arc<EpochSchedule>, InstructionError> {
50 self.epoch_schedule
51 .clone()
52 .ok_or(InstructionError::UnsupportedSysvar)
53 }
54
55 pub fn set_epoch_schedule(&mut self, epoch_schedule: EpochSchedule) {
56 self.epoch_schedule = Some(Arc::new(epoch_schedule));
57 }
58
59 #[deprecated]
60 #[allow(deprecated)]
61 pub fn get_fees(&self) -> Result<Arc<Fees>, InstructionError> {
62 self.fees.clone().ok_or(InstructionError::UnsupportedSysvar)
63 }
64
65 #[deprecated]
66 #[allow(deprecated)]
67 pub fn set_fees(&mut self, fees: Fees) {
68 self.fees = Some(Arc::new(fees));
69 }
70
71 pub fn get_rent(&self) -> Result<Arc<Rent>, InstructionError> {
72 self.rent.clone().ok_or(InstructionError::UnsupportedSysvar)
73 }
74
75 pub fn set_rent(&mut self, rent: Rent) {
76 self.rent = Some(Arc::new(rent));
77 }
78
79 pub fn get_slot_hashes(&self) -> Result<Arc<SlotHashes>, InstructionError> {
80 self.slot_hashes
81 .clone()
82 .ok_or(InstructionError::UnsupportedSysvar)
83 }
84
85 pub fn set_slot_hashes(&mut self, slot_hashes: SlotHashes) {
86 self.slot_hashes = Some(Arc::new(slot_hashes));
87 }
88
89 #[deprecated]
90 #[allow(deprecated)]
91 pub fn get_recent_blockhashes(&self) -> Result<Arc<RecentBlockhashes>, InstructionError> {
92 self.recent_blockhashes
93 .clone()
94 .ok_or(InstructionError::UnsupportedSysvar)
95 }
96
97 #[deprecated]
98 #[allow(deprecated)]
99 pub fn set_recent_blockhashes(&mut self, recent_blockhashes: RecentBlockhashes) {
100 self.recent_blockhashes = Some(Arc::new(recent_blockhashes));
101 }
102
103 pub fn get_stake_history(&self) -> Result<Arc<StakeHistory>, InstructionError> {
104 self.stake_history
105 .clone()
106 .ok_or(InstructionError::UnsupportedSysvar)
107 }
108
109 pub fn set_stake_history(&mut self, stake_history: StakeHistory) {
110 self.stake_history = Some(Arc::new(stake_history));
111 }
112
113 pub fn fill_missing_entries<F: FnMut(&Pubkey, &mut dyn FnMut(&[u8]))>(
114 &mut self,
115 mut get_account_data: F,
116 ) {
117 if self.clock.is_none() {
118 get_account_data(&Clock::id(), &mut |data: &[u8]| {
119 if let Ok(clock) = bincode::deserialize(data) {
120 self.set_clock(clock);
121 }
122 });
123 }
124 if self.epoch_schedule.is_none() {
125 get_account_data(&EpochSchedule::id(), &mut |data: &[u8]| {
126 if let Ok(epoch_schedule) = bincode::deserialize(data) {
127 self.set_epoch_schedule(epoch_schedule);
128 }
129 });
130 }
131 #[allow(deprecated)]
132 if self.fees.is_none() {
133 get_account_data(&Fees::id(), &mut |data: &[u8]| {
134 if let Ok(fees) = bincode::deserialize(data) {
135 self.set_fees(fees);
136 }
137 });
138 }
139 if self.rent.is_none() {
140 get_account_data(&Rent::id(), &mut |data: &[u8]| {
141 if let Ok(rent) = bincode::deserialize(data) {
142 self.set_rent(rent);
143 }
144 });
145 }
146 if self.slot_hashes.is_none() {
147 get_account_data(&SlotHashes::id(), &mut |data: &[u8]| {
148 if let Ok(slot_hashes) = bincode::deserialize(data) {
149 self.set_slot_hashes(slot_hashes);
150 }
151 });
152 }
153 #[allow(deprecated)]
154 if self.recent_blockhashes.is_none() {
155 get_account_data(&RecentBlockhashes::id(), &mut |data: &[u8]| {
156 if let Ok(recent_blockhashes) = bincode::deserialize(data) {
157 self.set_recent_blockhashes(recent_blockhashes);
158 }
159 });
160 }
161 if self.stake_history.is_none() {
162 get_account_data(&StakeHistory::id(), &mut |data: &[u8]| {
163 if let Ok(stake_history) = bincode::deserialize(data) {
164 self.set_stake_history(stake_history);
165 }
166 });
167 }
168 }
169
170 pub fn reset(&mut self) {
171 *self = SysvarCache::default();
172 }
173}
174
175pub mod get_sysvar_with_account_check {
181 use super::*;
182
183 fn check_sysvar_account<S: Sysvar>(
184 transaction_context: &TransactionContext,
185 instruction_context: &InstructionContext,
186 instruction_account_index: IndexOfAccount,
187 ) -> Result<(), InstructionError> {
188 let index_in_transaction = instruction_context
189 .get_index_of_instruction_account_in_transaction(instruction_account_index)?;
190 if !S::check_id(transaction_context.get_key_of_account_at_index(index_in_transaction)?) {
191 return Err(InstructionError::InvalidArgument);
192 }
193 Ok(())
194 }
195
196 pub fn clock(
197 invoke_context: &InvokeContext,
198 instruction_context: &InstructionContext,
199 instruction_account_index: IndexOfAccount,
200 ) -> Result<Arc<Clock>, InstructionError> {
201 check_sysvar_account::<Clock>(
202 invoke_context.transaction_context,
203 instruction_context,
204 instruction_account_index,
205 )?;
206 invoke_context.get_sysvar_cache().get_clock()
207 }
208
209 pub fn rent(
210 invoke_context: &InvokeContext,
211 instruction_context: &InstructionContext,
212 instruction_account_index: IndexOfAccount,
213 ) -> Result<Arc<Rent>, InstructionError> {
214 check_sysvar_account::<Rent>(
215 invoke_context.transaction_context,
216 instruction_context,
217 instruction_account_index,
218 )?;
219 invoke_context.get_sysvar_cache().get_rent()
220 }
221
222 pub fn slot_hashes(
223 invoke_context: &InvokeContext,
224 instruction_context: &InstructionContext,
225 instruction_account_index: IndexOfAccount,
226 ) -> Result<Arc<SlotHashes>, InstructionError> {
227 check_sysvar_account::<SlotHashes>(
228 invoke_context.transaction_context,
229 instruction_context,
230 instruction_account_index,
231 )?;
232 invoke_context.get_sysvar_cache().get_slot_hashes()
233 }
234
235 #[allow(deprecated)]
236 pub fn recent_blockhashes(
237 invoke_context: &InvokeContext,
238 instruction_context: &InstructionContext,
239 instruction_account_index: IndexOfAccount,
240 ) -> Result<Arc<RecentBlockhashes>, InstructionError> {
241 check_sysvar_account::<RecentBlockhashes>(
242 invoke_context.transaction_context,
243 instruction_context,
244 instruction_account_index,
245 )?;
246 invoke_context.get_sysvar_cache().get_recent_blockhashes()
247 }
248
249 pub fn stake_history(
250 invoke_context: &InvokeContext,
251 instruction_context: &InstructionContext,
252 instruction_account_index: IndexOfAccount,
253 ) -> Result<Arc<StakeHistory>, InstructionError> {
254 check_sysvar_account::<StakeHistory>(
255 invoke_context.transaction_context,
256 instruction_context,
257 instruction_account_index,
258 )?;
259 invoke_context.get_sysvar_cache().get_stake_history()
260 }
261}