solana_slot_hashes/
lib.rs1#![cfg_attr(docsrs, feature(doc_cfg))]
9
10#[cfg(feature = "sysvar")]
11pub mod sysvar;
12
13use {
14 solana_hash::Hash,
15 std::{
16 iter::FromIterator,
17 ops::Deref,
18 sync::atomic::{AtomicUsize, Ordering},
19 },
20};
21
22pub const MAX_ENTRIES: usize = 512; static NUM_ENTRIES: AtomicUsize = AtomicUsize::new(MAX_ENTRIES);
27
28pub fn get_entries() -> usize {
29 NUM_ENTRIES.load(Ordering::Relaxed)
30}
31
32pub fn set_entries_for_tests_only(entries: usize) {
33 NUM_ENTRIES.store(entries, Ordering::Relaxed);
34}
35
36pub type SlotHash = (u64, Hash);
37
38const LEN_PREFIX: usize = size_of::<u64>();
39const SLOT_HASH_SERIALIZED_SIZE: usize = size_of::<u64>() + size_of::<Hash>();
40
41pub const SIZE: usize = LEN_PREFIX + MAX_ENTRIES * SLOT_HASH_SERIALIZED_SIZE;
43const _: () = assert!(SIZE == 20_488);
44
45#[repr(C)]
46#[cfg_attr(
47 feature = "serde",
48 derive(serde_derive::Deserialize, serde_derive::Serialize)
49)]
50#[cfg_attr(feature = "wincode", derive(wincode::SchemaWrite, wincode::SchemaRead))]
51#[derive(PartialEq, Eq, Debug, Default)]
52pub struct SlotHashes(Vec<SlotHash>);
53
54impl SlotHashes {
55 pub fn add(&mut self, slot: u64, hash: Hash) {
56 match self.binary_search_by(|(probe, _)| slot.cmp(probe)) {
57 Ok(index) => (self.0)[index] = (slot, hash),
58 Err(index) => (self.0).insert(index, (slot, hash)),
59 }
60 (self.0).truncate(get_entries());
61 }
62 pub fn position(&self, slot: &u64) -> Option<usize> {
63 self.binary_search_by(|(probe, _)| slot.cmp(probe)).ok()
64 }
65 #[allow(clippy::trivially_copy_pass_by_ref)]
66 pub fn get(&self, slot: &u64) -> Option<&Hash> {
67 self.binary_search_by(|(probe, _)| slot.cmp(probe))
68 .ok()
69 .map(|index| &self[index].1)
70 }
71 pub fn new(slot_hashes: &[SlotHash]) -> Self {
72 let mut slot_hashes = slot_hashes.to_vec();
73 slot_hashes.sort_by(|(a, _), (b, _)| b.cmp(a));
74 Self(slot_hashes)
75 }
76 pub fn slot_hashes(&self) -> &[SlotHash] {
77 &self.0
78 }
79}
80
81impl FromIterator<(u64, Hash)> for SlotHashes {
82 fn from_iter<I: IntoIterator<Item = (u64, Hash)>>(iter: I) -> Self {
83 Self(iter.into_iter().collect())
84 }
85}
86
87impl Deref for SlotHashes {
88 type Target = Vec<SlotHash>;
89 fn deref(&self) -> &Self::Target {
90 &self.0
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use {super::*, solana_sha256_hasher::hash};
97
98 #[test]
99 fn test_size_of() {
100 let slot_hashes = SlotHashes(vec![(0, Hash::default()); MAX_ENTRIES]);
101 assert_eq!(
102 wincode::serialized_size(&slot_hashes).unwrap() as usize,
103 SIZE,
104 );
105 }
106
107 #[test]
108 fn test() {
109 let mut slot_hashes = SlotHashes::new(&[(1, Hash::default()), (3, Hash::default())]);
110 slot_hashes.add(2, Hash::default());
111 assert_eq!(
112 slot_hashes,
113 SlotHashes(vec![
114 (3, Hash::default()),
115 (2, Hash::default()),
116 (1, Hash::default()),
117 ])
118 );
119
120 let mut slot_hashes = SlotHashes::new(&[]);
121 for i in 0..MAX_ENTRIES + 1 {
122 slot_hashes.add(
123 i as u64,
124 hash(&[(i >> 24) as u8, (i >> 16) as u8, (i >> 8) as u8, i as u8]),
125 );
126 }
127 for i in 0..MAX_ENTRIES {
128 assert_eq!(slot_hashes[i].0, (MAX_ENTRIES - i) as u64);
129 }
130
131 assert_eq!(slot_hashes.len(), MAX_ENTRIES);
132 }
133}