solana_program/
clock.rs

1//! Information about the network's clock, ticks, slots, etc.
2
3use {
4    crate::{clone_zeroed, copy_field},
5    std::mem::MaybeUninit,
6};
7
8// The default tick rate that the cluster attempts to achieve.  Note that the actual tick
9// rate at any given time should be expected to drift
10pub const DEFAULT_TICKS_PER_SECOND: u64 = 160;
11
12#[cfg(test)]
13static_assertions::const_assert_eq!(MS_PER_TICK, 6);
14pub const MS_PER_TICK: u64 = 1000 / DEFAULT_TICKS_PER_SECOND;
15
16#[cfg(test)]
17static_assertions::const_assert_eq!(SLOT_MS, 400);
18pub const SLOT_MS: u64 = (DEFAULT_TICKS_PER_SLOT * 1000) / DEFAULT_TICKS_PER_SECOND;
19
20// At 160 ticks/s, 64 ticks per slot implies that leader rotation and voting will happen
21// every 400 ms. A fast voting cadence ensures faster finality and convergence
22pub const DEFAULT_TICKS_PER_SLOT: u64 = 64;
23
24// GCP n1-standard hardware and also a xeon e5-2520 v4 are about this rate of hashes/s
25pub const DEFAULT_HASHES_PER_SECOND: u64 = 2_000_000;
26
27#[cfg(test)]
28static_assertions::const_assert_eq!(DEFAULT_HASHES_PER_TICK, 12_500);
29pub const DEFAULT_HASHES_PER_TICK: u64 = DEFAULT_HASHES_PER_SECOND / DEFAULT_TICKS_PER_SECOND;
30
31// 1 Dev Epoch = 400 ms * 8192 ~= 55 minutes
32pub const DEFAULT_DEV_SLOTS_PER_EPOCH: u64 = 8192;
33
34#[cfg(test)]
35static_assertions::const_assert_eq!(SECONDS_PER_DAY, 86_400);
36pub const SECONDS_PER_DAY: u64 = 24 * 60 * 60;
37
38#[cfg(test)]
39static_assertions::const_assert_eq!(TICKS_PER_DAY, 13_824_000);
40pub const TICKS_PER_DAY: u64 = DEFAULT_TICKS_PER_SECOND * SECONDS_PER_DAY;
41
42#[cfg(test)]
43static_assertions::const_assert_eq!(DEFAULT_SLOTS_PER_EPOCH, 432_000);
44// 1 Epoch ~= 2 days
45pub const DEFAULT_SLOTS_PER_EPOCH: u64 = 2 * TICKS_PER_DAY / DEFAULT_TICKS_PER_SLOT;
46
47// leader schedule is governed by this
48pub const NUM_CONSECUTIVE_LEADER_SLOTS: u64 = 4;
49
50#[cfg(test)]
51static_assertions::const_assert_eq!(DEFAULT_MS_PER_SLOT, 400);
52pub const DEFAULT_MS_PER_SLOT: u64 = 1_000 * DEFAULT_TICKS_PER_SLOT / DEFAULT_TICKS_PER_SECOND;
53pub const DEFAULT_S_PER_SLOT: f64 = DEFAULT_TICKS_PER_SLOT as f64 / DEFAULT_TICKS_PER_SECOND as f64;
54
55/// The time window of recent block hash values that the bank will track the signatures
56/// of over. Once the bank discards a block hash, it will reject any transactions that use
57/// that `recent_blockhash` in a transaction. Lowering this value reduces memory consumption,
58/// but requires clients to update its `recent_blockhash` more frequently. Raising the value
59/// lengthens the time a client must wait to be certain a missing transaction will
60/// not be processed by the network.
61pub const MAX_HASH_AGE_IN_SECONDS: usize = 120;
62
63#[cfg(test)]
64static_assertions::const_assert_eq!(MAX_RECENT_BLOCKHASHES, 300);
65// Number of maximum recent blockhashes (one blockhash per non-skipped slot)
66pub const MAX_RECENT_BLOCKHASHES: usize =
67    MAX_HASH_AGE_IN_SECONDS * DEFAULT_TICKS_PER_SECOND as usize / DEFAULT_TICKS_PER_SLOT as usize;
68
69#[cfg(test)]
70static_assertions::const_assert_eq!(MAX_PROCESSING_AGE, 150);
71// The maximum age of a blockhash that will be accepted by the leader
72pub const MAX_PROCESSING_AGE: usize = MAX_RECENT_BLOCKHASHES / 2;
73
74/// This is maximum time consumed in forwarding a transaction from one node to next, before
75/// it can be processed in the target node
76pub const MAX_TRANSACTION_FORWARDING_DELAY_GPU: usize = 2;
77
78/// More delay is expected if CUDA is not enabled (as signature verification takes longer)
79pub const MAX_TRANSACTION_FORWARDING_DELAY: usize = 6;
80
81/// Slot is a unit of time given to a leader for encoding,
82///  is some some number of Ticks long.
83pub type Slot = u64;
84
85/// Uniquely distinguishes every version of a slot, even if the
86/// slot number is the same, i.e. duplicate slots
87pub type BankId = u64;
88
89/// Epoch is a unit of time a given leader schedule is honored,
90///  some number of Slots.
91pub type Epoch = u64;
92
93pub const GENESIS_EPOCH: Epoch = 0;
94// must be sync with Account::rent_epoch::default()
95pub const INITIAL_RENT_EPOCH: Epoch = 0;
96
97/// SlotIndex is an index to the slots of a epoch
98pub type SlotIndex = u64;
99
100/// SlotCount is the number of slots in a epoch
101pub type SlotCount = u64;
102
103/// UnixTimestamp is an approximate measure of real-world time,
104/// expressed as Unix time (ie. seconds since the Unix epoch)
105pub type UnixTimestamp = i64;
106
107/// Clock represents network time.  Members of Clock start from 0 upon
108///  network boot.  The best way to map Clock to wallclock time is to use
109///  current Slot, as Epochs vary in duration (they start short and grow
110///  as the network progresses).
111///
112#[repr(C)]
113#[derive(Serialize, Deserialize, Debug, Default, PartialEq, Eq)]
114pub struct Clock {
115    /// the current network/bank Slot
116    pub slot: Slot,
117    /// the timestamp of the first Slot in this Epoch
118    pub epoch_start_timestamp: UnixTimestamp,
119    /// the bank Epoch
120    pub epoch: Epoch,
121    /// the future Epoch for which the leader schedule has
122    ///  most recently been calculated
123    pub leader_schedule_epoch: Epoch,
124    /// originally computed from genesis creation time and network time
125    /// in slots (drifty); corrected using validator timestamp oracle as of
126    /// timestamp_correction and timestamp_bounding features
127    pub unix_timestamp: UnixTimestamp,
128}
129
130impl Clone for Clock {
131    fn clone(&self) -> Self {
132        clone_zeroed(|cloned: &mut MaybeUninit<Self>| {
133            let ptr = cloned.as_mut_ptr();
134            unsafe {
135                copy_field!(ptr, self, slot);
136                copy_field!(ptr, self, epoch_start_timestamp);
137                copy_field!(ptr, self, epoch);
138                copy_field!(ptr, self, leader_schedule_epoch);
139                copy_field!(ptr, self, unix_timestamp);
140            }
141        })
142    }
143}
144
145#[cfg(test)]
146mod tests {
147    use super::*;
148
149    #[test]
150    fn test_clone() {
151        let clock = Clock {
152            slot: 1,
153            epoch_start_timestamp: 2,
154            epoch: 3,
155            leader_schedule_epoch: 4,
156            unix_timestamp: 5,
157        };
158        let cloned_clock = clock.clone();
159        assert_eq!(cloned_clock, clock);
160    }
161}