solana_sysvar/clock.rs
1//! Information about the network’s clock, ticks, slots, etc.
2//!
3//! The _clock sysvar_ provides access to the [`Clock`] type, which includes the
4//! current slot, the current epoch, and the approximate real-world time of the
5//! slot.
6//!
7//! [`Clock`] implements [`Sysvar::get`] and can be loaded efficiently without
8//! passing the sysvar account ID to the program.
9//!
10//! See also the Solana [documentation on the clock sysvar][sdoc].
11//!
12//! [sdoc]: https://docs.solanalabs.com/runtime/sysvars#clock
13//!
14//! # Examples
15//!
16//! Accessing via on-chain program directly:
17//!
18//! ```no_run
19//! # use solana_account_info::AccountInfo;
20//! # use solana_clock::Clock;
21//! # use solana_msg::msg;
22//! # use solana_program_error::{ProgramError, ProgramResult};
23//! # use solana_pubkey::Pubkey;
24//! # use solana_sysvar::Sysvar;
25//! #
26//! fn process_instruction(
27//! program_id: &Pubkey,
28//! accounts: &[AccountInfo],
29//! instruction_data: &[u8],
30//! ) -> ProgramResult {
31//!
32//! let clock = Clock::get()?;
33//! msg!("clock: {:#?}", clock);
34//!
35//! Ok(())
36//! }
37//! #
38//! # use solana_sysvar_id::SysvarId;
39//! # let p = Clock::id();
40//! # let l = &mut 1169280;
41//! # let d = &mut vec![240, 153, 233, 7, 0, 0, 0, 0, 11, 115, 118, 98, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 0, 0, 52, 1, 0, 0, 0, 0, 0, 0, 121, 50, 119, 98, 0, 0, 0, 0];
42//! # let a = AccountInfo::new(&p, false, false, l, d, &p, false);
43//! # let accounts = &[a.clone(), a];
44//! # process_instruction(
45//! # &Pubkey::new_unique(),
46//! # accounts,
47//! # &[],
48//! # )?;
49//! # Ok::<(), ProgramError>(())
50//! ```
51//!
52//! Accessing via on-chain program's account parameters:
53//!
54//! ```
55//! # use solana_account_info::{AccountInfo, next_account_info};
56//! # use solana_clock::Clock;
57//! # use solana_msg::msg;
58//! # use solana_program_error::{ProgramError, ProgramResult};
59//! # use solana_pubkey::Pubkey;
60//! # use solana_sysvar::{Sysvar, SysvarSerialize};
61//! # use solana_sdk_ids::sysvar::clock;
62//! #
63//! fn process_instruction(
64//! program_id: &Pubkey,
65//! accounts: &[AccountInfo],
66//! instruction_data: &[u8],
67//! ) -> ProgramResult {
68//! let account_info_iter = &mut accounts.iter();
69//! let clock_account_info = next_account_info(account_info_iter)?;
70//!
71//! assert!(clock::check_id(clock_account_info.key));
72//!
73//! let clock = Clock::from_account_info(clock_account_info)?;
74//! msg!("clock: {:#?}", clock);
75//!
76//! Ok(())
77//! }
78//! #
79//! # use solana_sysvar_id::SysvarId;
80//! # let p = Clock::id();
81//! # let l = &mut 1169280;
82//! # let d = &mut vec![240, 153, 233, 7, 0, 0, 0, 0, 11, 115, 118, 98, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 0, 0, 52, 1, 0, 0, 0, 0, 0, 0, 121, 50, 119, 98, 0, 0, 0, 0];
83//! # let a = AccountInfo::new(&p, false, false, l, d, &p, false);
84//! # let accounts = &[a.clone(), a];
85//! # process_instruction(
86//! # &Pubkey::new_unique(),
87//! # accounts,
88//! # &[],
89//! # )?;
90//! # Ok::<(), ProgramError>(())
91//! ```
92//!
93//! Accessing via the RPC client:
94//!
95//! ```
96//! # use solana_clock::Clock;
97//! # use solana_example_mocks::solana_account;
98//! # use solana_example_mocks::solana_rpc_client;
99//! # use solana_rpc_client::rpc_client::RpcClient;
100//! # use solana_account::Account;
101//! # use solana_sdk_ids::sysvar::clock;
102//! # use anyhow::Result;
103//! #
104//! fn print_sysvar_clock(client: &RpcClient) -> Result<()> {
105//! # client.set_get_account_response(clock::ID, Account {
106//! # lamports: 1169280,
107//! # data: vec![240, 153, 233, 7, 0, 0, 0, 0, 11, 115, 118, 98, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 0, 0, 52, 1, 0, 0, 0, 0, 0, 0, 121, 50, 119, 98, 0, 0, 0, 0],
108//! # owner: solana_sdk_ids::system_program::ID,
109//! # executable: false,
110//! # });
111//! #
112//! let clock = client.get_account(&clock::ID)?;
113//! let data: Clock = bincode::deserialize(&clock.data)?;
114//!
115//! Ok(())
116//! }
117//! #
118//! # let client = RpcClient::new(String::new());
119//! # print_sysvar_clock(&client)?;
120//! #
121//! # Ok::<(), anyhow::Error>(())
122//! ```
123
124#[cfg(feature = "bincode")]
125use crate::SysvarSerialize;
126use crate::{impl_sysvar_get, Sysvar};
127pub use {
128 solana_clock::Clock,
129 solana_sdk_ids::sysvar::clock::{check_id, id, ID},
130};
131
132impl Sysvar for Clock {
133 impl_sysvar_get!(id());
134}
135
136#[cfg(feature = "bincode")]
137impl SysvarSerialize for Clock {}
138
139#[cfg(test)]
140mod tests {
141 use {super::*, crate::tests::to_bytes, serial_test::serial};
142
143 #[test]
144 #[serial]
145 fn test_clock_get_uses_sysvar_syscall() {
146 let expected = Clock {
147 slot: 1,
148 epoch_start_timestamp: 2,
149 epoch: 3,
150 leader_schedule_epoch: 4,
151 unix_timestamp: 5,
152 };
153
154 let data = to_bytes(&expected);
155 crate::tests::mock_get_sysvar_syscall(&data);
156
157 let got = Clock::get().unwrap();
158 assert_eq!(got, expected);
159 }
160
161 struct ValidateIdSyscall {
162 data: Vec<u8>,
163 }
164
165 impl crate::program_stubs::SyscallStubs for ValidateIdSyscall {
166 fn sol_get_sysvar(
167 &self,
168 sysvar_id_addr: *const u8,
169 var_addr: *mut u8,
170 offset: u64,
171 length: u64,
172 ) -> u64 {
173 // Validate that the macro passed the correct sysvar id pointer
174 let passed_id = unsafe { *(sysvar_id_addr as *const solana_pubkey::Pubkey) };
175 assert_eq!(passed_id, id());
176
177 let slice = unsafe { std::slice::from_raw_parts_mut(var_addr, length as usize) };
178 slice.copy_from_slice(
179 &self.data[offset as usize..(offset.saturating_add(length)) as usize],
180 );
181 solana_program_entrypoint::SUCCESS
182 }
183 }
184
185 #[test]
186 #[serial]
187 fn test_clock_get_passes_correct_sysvar_id() {
188 let expected = Clock {
189 slot: 11,
190 epoch_start_timestamp: 22,
191 epoch: 33,
192 leader_schedule_epoch: 44,
193 unix_timestamp: 55,
194 };
195 let data = to_bytes(&expected);
196 let prev = crate::program_stubs::set_syscall_stubs(Box::new(ValidateIdSyscall { data }));
197
198 let got = Clock::get().unwrap();
199 assert_eq!(got, expected);
200
201 let _ = crate::program_stubs::set_syscall_stubs(prev);
202 }
203}