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 = "serde")]
22use serde_derive::{Deserialize, Serialize};
23pub use solana_sdk_ids::sysvar::recent_blockhashes::{check_id, id, ID};
24use {
25    crate::Sysvar,
26    solana_fee_calculator::FeeCalculator,
27    solana_hash::Hash,
28    solana_sysvar_id::impl_sysvar_id,
29    std::{cmp::Ordering, collections::BinaryHeap, iter::FromIterator, ops::Deref},
30};
31
32#[deprecated(
33    since = "1.9.0",
34    note = "Please do not use, will no longer be available in the future"
35)]
36pub const MAX_ENTRIES: usize = 150;
37
38const LEN_PREFIX: usize = size_of::<u64>();
39const ENTRY_SERIALIZED_SIZE: usize = size_of::<Hash>() + size_of::<FeeCalculator>();
40
41/// Serialized size of `RecentBlockhashes` sysvar account.
42pub const SIZE: usize = LEN_PREFIX + (MAX_ENTRIES * ENTRY_SERIALIZED_SIZE);
43const _: () = assert!(SIZE == 6_008);
44
45impl_sysvar_id!(RecentBlockhashes);
46
47#[deprecated(
48    since = "1.9.0",
49    note = "Please do not use, will no longer be available in the future"
50)]
51#[repr(C)]
52#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
53#[cfg_attr(feature = "wincode", derive(wincode::SchemaWrite, wincode::SchemaRead))]
54#[derive(Clone, Debug, Default, PartialEq, Eq)]
55pub struct Entry {
56    pub blockhash: Hash,
57    pub fee_calculator: FeeCalculator,
58}
59impl Entry {
60    pub fn new(blockhash: &Hash, lamports_per_signature: u64) -> Self {
61        Self {
62            blockhash: *blockhash,
63            fee_calculator: FeeCalculator::new(lamports_per_signature),
64        }
65    }
66}
67
68#[deprecated(
69    since = "1.9.0",
70    note = "Please do not use, will no longer be available in the future"
71)]
72#[derive(Clone, Debug)]
73pub struct IterItem<'a>(pub u64, pub &'a Hash, pub u64);
74
75impl Eq for IterItem<'_> {}
76
77impl PartialEq for IterItem<'_> {
78    fn eq(&self, other: &Self) -> bool {
79        self.0 == other.0
80    }
81}
82
83impl Ord for IterItem<'_> {
84    fn cmp(&self, other: &Self) -> Ordering {
85        self.0.cmp(&other.0)
86    }
87}
88
89impl PartialOrd for IterItem<'_> {
90    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
91        Some(self.cmp(other))
92    }
93}
94
95/// Contains recent block hashes and fee calculators.
96///
97/// The entries are ordered by descending block height, so the first entry holds
98/// the most recent block hash, and the last entry holds an old block hash.
99#[deprecated(
100    since = "1.9.0",
101    note = "Please do not use, will no longer be available in the future"
102)]
103#[repr(C)]
104#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
105#[cfg_attr(feature = "wincode", derive(wincode::SchemaWrite, wincode::SchemaRead))]
106#[derive(Clone, Debug, PartialEq, Eq)]
107pub struct RecentBlockhashes(Vec<Entry>);
108
109impl Default for RecentBlockhashes {
110    fn default() -> Self {
111        Self(Vec::with_capacity(MAX_ENTRIES))
112    }
113}
114
115impl<'a> FromIterator<IterItem<'a>> for RecentBlockhashes {
116    fn from_iter<I>(iter: I) -> Self
117    where
118        I: IntoIterator<Item = IterItem<'a>>,
119    {
120        let mut new = Self::default();
121        for i in iter {
122            new.0.push(Entry::new(i.1, i.2))
123        }
124        new
125    }
126}
127
128// This is cherry-picked from HEAD of rust-lang's master (ref1) because it's
129// a nightly-only experimental API.
130// (binary_heap_into_iter_sorted [rustc issue #59278])
131// Remove this and use the standard API once BinaryHeap::into_iter_sorted (ref2)
132// is stabilized.
133// ref1: https://github.com/rust-lang/rust/blob/2f688ac602d50129388bb2a5519942049096cbff/src/liballoc/collections/binary_heap.rs#L1149
134// ref2: https://doc.rust-lang.org/std/collections/struct.BinaryHeap.html#into_iter_sorted.v
135
136#[derive(Clone, Debug)]
137pub struct IntoIterSorted<T> {
138    inner: BinaryHeap<T>,
139}
140impl<T> IntoIterSorted<T> {
141    pub fn new(binary_heap: BinaryHeap<T>) -> Self {
142        Self { inner: binary_heap }
143    }
144}
145
146impl<T: Ord> Iterator for IntoIterSorted<T> {
147    type Item = T;
148
149    #[inline]
150    fn next(&mut self) -> Option<T> {
151        self.inner.pop()
152    }
153
154    #[inline]
155    fn size_hint(&self) -> (usize, Option<usize>) {
156        let exact = self.inner.len();
157        (exact, Some(exact))
158    }
159}
160
161impl Sysvar for RecentBlockhashes {}
162
163impl Deref for RecentBlockhashes {
164    type Target = Vec<Entry>;
165    fn deref(&self) -> &Self::Target {
166        &self.0
167    }
168}
169
170#[cfg(test)]
171mod tests {
172    use {super::*, solana_clock::MAX_PROCESSING_AGE};
173
174    #[test]
175    #[allow(clippy::assertions_on_constants)]
176    fn test_sysvar_can_hold_all_active_blockhashes() {
177        // Ensure we can still hold all of the active entries in `BlockhashQueue`
178        assert!(MAX_PROCESSING_AGE <= MAX_ENTRIES);
179    }
180}