Skip to main content

solana_sysvar/
recent_blockhashes.rs

1//! Information about recent blocks and their fee calculators.
2//!
3//! The _recent blockhashes sysvar_ provides access to the [`RecentBlockhashes`],
4//! which contains recent blockhahes and their [`FeeCalculator`]s.
5//!
6//! [`RecentBlockhashes`] does not implement [`Sysvar::get`].
7//!
8//! This sysvar is deprecated and should not be used. Transaction fees should be
9//! determined with the [`getFeeForMessage`] RPC method. For additional context
10//! see the [Comprehensive Compute Fees proposal][ccf].
11//!
12//! [`getFeeForMessage`]: https://solana.com/docs/rpc/http/getfeeformessage
13//! [ccf]: https://docs.solanalabs.com/proposals/comprehensive-compute-fees
14//!
15//! See also the Solana [documentation on the recent blockhashes sysvar][sdoc].
16//!
17//! [sdoc]: https://docs.solanalabs.com/runtime/sysvars#recentblockhashes
18
19#![allow(deprecated)]
20#![allow(clippy::arithmetic_side_effects)]
21#[cfg(feature = "bincode")]
22use crate::SysvarSerialize;
23#[cfg(feature = "serde")]
24use serde_derive::{Deserialize, Serialize};
25pub use solana_sdk_ids::sysvar::recent_blockhashes::{check_id, id, ID};
26use {
27    crate::Sysvar,
28    solana_fee_calculator::FeeCalculator,
29    solana_hash::Hash,
30    solana_sysvar_id::impl_sysvar_id,
31    std::{cmp::Ordering, collections::BinaryHeap, iter::FromIterator, ops::Deref},
32};
33
34#[deprecated(
35    since = "1.9.0",
36    note = "Please do not use, will no longer be available in the future"
37)]
38pub const MAX_ENTRIES: usize = 150;
39
40const LEN_PREFIX: usize = size_of::<u64>();
41const ENTRY_SERIALIZED_SIZE: usize = size_of::<Hash>() + size_of::<FeeCalculator>();
42
43/// Serialized size of `RecentBlockhashes` sysvar account.
44pub const SIZE: usize = LEN_PREFIX + (MAX_ENTRIES * ENTRY_SERIALIZED_SIZE);
45const _: () = assert!(SIZE == 6_008);
46
47impl_sysvar_id!(RecentBlockhashes);
48
49#[deprecated(
50    since = "1.9.0",
51    note = "Please do not use, will no longer be available in the future"
52)]
53#[repr(C)]
54#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
55#[cfg_attr(feature = "wincode", derive(wincode::SchemaWrite, wincode::SchemaRead))]
56#[derive(Clone, Debug, Default, PartialEq, Eq)]
57pub struct Entry {
58    pub blockhash: Hash,
59    pub fee_calculator: FeeCalculator,
60}
61impl Entry {
62    pub fn new(blockhash: &Hash, lamports_per_signature: u64) -> Self {
63        Self {
64            blockhash: *blockhash,
65            fee_calculator: FeeCalculator::new(lamports_per_signature),
66        }
67    }
68}
69
70#[deprecated(
71    since = "1.9.0",
72    note = "Please do not use, will no longer be available in the future"
73)]
74#[derive(Clone, Debug)]
75pub struct IterItem<'a>(pub u64, pub &'a Hash, pub u64);
76
77impl Eq for IterItem<'_> {}
78
79impl PartialEq for IterItem<'_> {
80    fn eq(&self, other: &Self) -> bool {
81        self.0 == other.0
82    }
83}
84
85impl Ord for IterItem<'_> {
86    fn cmp(&self, other: &Self) -> Ordering {
87        self.0.cmp(&other.0)
88    }
89}
90
91impl PartialOrd for IterItem<'_> {
92    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
93        Some(self.cmp(other))
94    }
95}
96
97/// Contains recent block hashes and fee calculators.
98///
99/// The entries are ordered by descending block height, so the first entry holds
100/// the most recent block hash, and the last entry holds an old block hash.
101#[deprecated(
102    since = "1.9.0",
103    note = "Please do not use, will no longer be available in the future"
104)]
105#[repr(C)]
106#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
107#[cfg_attr(feature = "wincode", derive(wincode::SchemaWrite, wincode::SchemaRead))]
108#[derive(Clone, Debug, PartialEq, Eq)]
109pub struct RecentBlockhashes(Vec<Entry>);
110
111impl Default for RecentBlockhashes {
112    fn default() -> Self {
113        Self(Vec::with_capacity(MAX_ENTRIES))
114    }
115}
116
117impl<'a> FromIterator<IterItem<'a>> for RecentBlockhashes {
118    fn from_iter<I>(iter: I) -> Self
119    where
120        I: IntoIterator<Item = IterItem<'a>>,
121    {
122        let mut new = Self::default();
123        for i in iter {
124            new.0.push(Entry::new(i.1, i.2))
125        }
126        new
127    }
128}
129
130// This is cherry-picked from HEAD of rust-lang's master (ref1) because it's
131// a nightly-only experimental API.
132// (binary_heap_into_iter_sorted [rustc issue #59278])
133// Remove this and use the standard API once BinaryHeap::into_iter_sorted (ref2)
134// is stabilized.
135// ref1: https://github.com/rust-lang/rust/blob/2f688ac602d50129388bb2a5519942049096cbff/src/liballoc/collections/binary_heap.rs#L1149
136// ref2: https://doc.rust-lang.org/std/collections/struct.BinaryHeap.html#into_iter_sorted.v
137
138#[derive(Clone, Debug)]
139pub struct IntoIterSorted<T> {
140    inner: BinaryHeap<T>,
141}
142impl<T> IntoIterSorted<T> {
143    pub fn new(binary_heap: BinaryHeap<T>) -> Self {
144        Self { inner: binary_heap }
145    }
146}
147
148impl<T: Ord> Iterator for IntoIterSorted<T> {
149    type Item = T;
150
151    #[inline]
152    fn next(&mut self) -> Option<T> {
153        self.inner.pop()
154    }
155
156    #[inline]
157    fn size_hint(&self) -> (usize, Option<usize>) {
158        let exact = self.inner.len();
159        (exact, Some(exact))
160    }
161}
162
163impl Sysvar for RecentBlockhashes {}
164
165#[cfg(feature = "bincode")]
166impl SysvarSerialize for RecentBlockhashes {
167    fn size_of() -> usize {
168        SIZE
169    }
170}
171
172impl Deref for RecentBlockhashes {
173    type Target = Vec<Entry>;
174    fn deref(&self) -> &Self::Target {
175        &self.0
176    }
177}
178
179#[cfg(test)]
180mod tests {
181    use {super::*, solana_clock::MAX_PROCESSING_AGE};
182
183    #[test]
184    #[allow(clippy::assertions_on_constants)]
185    fn test_sysvar_can_hold_all_active_blockhashes() {
186        // Ensure we can still hold all of the active entries in `BlockhashQueue`
187        assert!(MAX_PROCESSING_AGE <= MAX_ENTRIES);
188    }
189
190    #[test]
191    fn test_size_of() {
192        let entry = Entry::new(&Hash::default(), 0);
193        assert_eq!(
194            bincode::serialized_size(&RecentBlockhashes(vec![entry; MAX_ENTRIES])).unwrap()
195                as usize,
196            RecentBlockhashes::size_of()
197        );
198    }
199}