forked from solana-labs/solana
-
Notifications
You must be signed in to change notification settings - Fork 168
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* extract slot-hashes crate * fix serde feature * fix sysvar doc link
- Loading branch information
1 parent
a4e43c8
commit 964f6d3
Showing
7 changed files
with
162 additions
and
110 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,109 +1 @@ | ||
//! A type to hold data for the [`SlotHashes` sysvar][sv]. | ||
//! | ||
//! [sv]: https://docs.solanalabs.com/runtime/sysvars#slothashes | ||
//! | ||
//! The sysvar ID is declared in [`sysvar::slot_hashes`]. | ||
//! | ||
//! [`sysvar::slot_hashes`]: crate::sysvar::slot_hashes | ||
|
||
pub use solana_clock::Slot; | ||
use { | ||
crate::hash::Hash, | ||
std::{ | ||
iter::FromIterator, | ||
ops::Deref, | ||
sync::atomic::{AtomicUsize, Ordering}, | ||
}, | ||
}; | ||
|
||
pub const MAX_ENTRIES: usize = 512; // about 2.5 minutes to get your vote in | ||
|
||
// This is to allow tests with custom slot hash expiry to avoid having to generate | ||
// 512 blocks for such tests. | ||
static NUM_ENTRIES: AtomicUsize = AtomicUsize::new(MAX_ENTRIES); | ||
|
||
pub fn get_entries() -> usize { | ||
NUM_ENTRIES.load(Ordering::Relaxed) | ||
} | ||
|
||
pub fn set_entries_for_tests_only(entries: usize) { | ||
NUM_ENTRIES.store(entries, Ordering::Relaxed); | ||
} | ||
|
||
pub type SlotHash = (Slot, Hash); | ||
|
||
#[repr(C)] | ||
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Default)] | ||
pub struct SlotHashes(Vec<SlotHash>); | ||
|
||
impl SlotHashes { | ||
pub fn add(&mut self, slot: Slot, hash: Hash) { | ||
match self.binary_search_by(|(probe, _)| slot.cmp(probe)) { | ||
Ok(index) => (self.0)[index] = (slot, hash), | ||
Err(index) => (self.0).insert(index, (slot, hash)), | ||
} | ||
(self.0).truncate(get_entries()); | ||
} | ||
pub fn position(&self, slot: &Slot) -> Option<usize> { | ||
self.binary_search_by(|(probe, _)| slot.cmp(probe)).ok() | ||
} | ||
#[allow(clippy::trivially_copy_pass_by_ref)] | ||
pub fn get(&self, slot: &Slot) -> Option<&Hash> { | ||
self.binary_search_by(|(probe, _)| slot.cmp(probe)) | ||
.ok() | ||
.map(|index| &self[index].1) | ||
} | ||
pub fn new(slot_hashes: &[SlotHash]) -> Self { | ||
let mut slot_hashes = slot_hashes.to_vec(); | ||
slot_hashes.sort_by(|(a, _), (b, _)| b.cmp(a)); | ||
Self(slot_hashes) | ||
} | ||
pub fn slot_hashes(&self) -> &[SlotHash] { | ||
&self.0 | ||
} | ||
} | ||
|
||
impl FromIterator<(Slot, Hash)> for SlotHashes { | ||
fn from_iter<I: IntoIterator<Item = (Slot, Hash)>>(iter: I) -> Self { | ||
Self(iter.into_iter().collect()) | ||
} | ||
} | ||
|
||
impl Deref for SlotHashes { | ||
type Target = Vec<SlotHash>; | ||
fn deref(&self) -> &Self::Target { | ||
&self.0 | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use {super::*, crate::hash::hash}; | ||
|
||
#[test] | ||
fn test() { | ||
let mut slot_hashes = SlotHashes::new(&[(1, Hash::default()), (3, Hash::default())]); | ||
slot_hashes.add(2, Hash::default()); | ||
assert_eq!( | ||
slot_hashes, | ||
SlotHashes(vec![ | ||
(3, Hash::default()), | ||
(2, Hash::default()), | ||
(1, Hash::default()), | ||
]) | ||
); | ||
|
||
let mut slot_hashes = SlotHashes::new(&[]); | ||
for i in 0..MAX_ENTRIES + 1 { | ||
slot_hashes.add( | ||
i as u64, | ||
hash(&[(i >> 24) as u8, (i >> 16) as u8, (i >> 8) as u8, i as u8]), | ||
); | ||
} | ||
for i in 0..MAX_ENTRIES { | ||
assert_eq!(slot_hashes[i].0, (MAX_ENTRIES - i) as u64); | ||
} | ||
|
||
assert_eq!(slot_hashes.len(), MAX_ENTRIES); | ||
} | ||
} | ||
pub use {solana_clock::Slot, solana_slot_hashes::*}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
[package] | ||
name = "solana-slot-hashes" | ||
description = "Types and utilities for the Solana SlotHashes sysvar." | ||
documentation = "https://docs.rs/solana-slot-hashes" | ||
version = { workspace = true } | ||
authors = { workspace = true } | ||
repository = { workspace = true } | ||
homepage = { workspace = true } | ||
license = { workspace = true } | ||
edition = { workspace = true } | ||
|
||
[dependencies] | ||
serde = { workspace = true, optional = true } | ||
serde_derive = { workspace = true, optional = true } | ||
solana-hash = { workspace = true, default-features = false } | ||
|
||
[dev-dependencies] | ||
solana-sha256-hasher = { workspace = true } | ||
|
||
[features] | ||
serde = ["dep:serde", "dep:serde_derive", "solana-hash/serde"] | ||
|
||
[package.metadata.docs.rs] | ||
targets = ["x86_64-unknown-linux-gnu"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
//! A type to hold data for the [`SlotHashes` sysvar][sv]. | ||
//! | ||
//! [sv]: https://docs.solanalabs.com/runtime/sysvars#slothashes | ||
//! | ||
//! The sysvar ID is declared in [`solana_program::sysvar::slot_hashes`]. | ||
//! | ||
//! [`solana_program::sysvar::slot_hashes`]: https://docs.rs/solana-program/latest/solana_program/sysvar/slot_hashes/index.html | ||
|
||
use { | ||
solana_hash::Hash, | ||
std::{ | ||
iter::FromIterator, | ||
ops::Deref, | ||
sync::atomic::{AtomicUsize, Ordering}, | ||
}, | ||
}; | ||
|
||
pub const MAX_ENTRIES: usize = 512; // about 2.5 minutes to get your vote in | ||
|
||
// This is to allow tests with custom slot hash expiry to avoid having to generate | ||
// 512 blocks for such tests. | ||
static NUM_ENTRIES: AtomicUsize = AtomicUsize::new(MAX_ENTRIES); | ||
|
||
pub fn get_entries() -> usize { | ||
NUM_ENTRIES.load(Ordering::Relaxed) | ||
} | ||
|
||
pub fn set_entries_for_tests_only(entries: usize) { | ||
NUM_ENTRIES.store(entries, Ordering::Relaxed); | ||
} | ||
|
||
pub type SlotHash = (u64, Hash); | ||
|
||
#[repr(C)] | ||
#[cfg_attr( | ||
feature = "serde", | ||
derive(serde_derive::Deserialize, serde_derive::Serialize) | ||
)] | ||
#[derive(PartialEq, Eq, Debug, Default)] | ||
pub struct SlotHashes(Vec<SlotHash>); | ||
|
||
impl SlotHashes { | ||
pub fn add(&mut self, slot: u64, hash: Hash) { | ||
match self.binary_search_by(|(probe, _)| slot.cmp(probe)) { | ||
Ok(index) => (self.0)[index] = (slot, hash), | ||
Err(index) => (self.0).insert(index, (slot, hash)), | ||
} | ||
(self.0).truncate(get_entries()); | ||
} | ||
pub fn position(&self, slot: &u64) -> Option<usize> { | ||
self.binary_search_by(|(probe, _)| slot.cmp(probe)).ok() | ||
} | ||
#[allow(clippy::trivially_copy_pass_by_ref)] | ||
pub fn get(&self, slot: &u64) -> Option<&Hash> { | ||
self.binary_search_by(|(probe, _)| slot.cmp(probe)) | ||
.ok() | ||
.map(|index| &self[index].1) | ||
} | ||
pub fn new(slot_hashes: &[SlotHash]) -> Self { | ||
let mut slot_hashes = slot_hashes.to_vec(); | ||
slot_hashes.sort_by(|(a, _), (b, _)| b.cmp(a)); | ||
Self(slot_hashes) | ||
} | ||
pub fn slot_hashes(&self) -> &[SlotHash] { | ||
&self.0 | ||
} | ||
} | ||
|
||
impl FromIterator<(u64, Hash)> for SlotHashes { | ||
fn from_iter<I: IntoIterator<Item = (u64, Hash)>>(iter: I) -> Self { | ||
Self(iter.into_iter().collect()) | ||
} | ||
} | ||
|
||
impl Deref for SlotHashes { | ||
type Target = Vec<SlotHash>; | ||
fn deref(&self) -> &Self::Target { | ||
&self.0 | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use {super::*, solana_sha256_hasher::hash}; | ||
|
||
#[test] | ||
fn test() { | ||
let mut slot_hashes = SlotHashes::new(&[(1, Hash::default()), (3, Hash::default())]); | ||
slot_hashes.add(2, Hash::default()); | ||
assert_eq!( | ||
slot_hashes, | ||
SlotHashes(vec![ | ||
(3, Hash::default()), | ||
(2, Hash::default()), | ||
(1, Hash::default()), | ||
]) | ||
); | ||
|
||
let mut slot_hashes = SlotHashes::new(&[]); | ||
for i in 0..MAX_ENTRIES + 1 { | ||
slot_hashes.add( | ||
i as u64, | ||
hash(&[(i >> 24) as u8, (i >> 16) as u8, (i >> 8) as u8, i as u8]), | ||
); | ||
} | ||
for i in 0..MAX_ENTRIES { | ||
assert_eq!(slot_hashes[i].0, (MAX_ENTRIES - i) as u64); | ||
} | ||
|
||
assert_eq!(slot_hashes.len(), MAX_ENTRIES); | ||
} | ||
} |