atlas_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://atlaschain.org/docs/rpc/http/getfeeformessage
13//! [ccf]: https://docs.atlaslabs.com/proposals/comprehensive-compute-fees
14//!
15//! See also the Atlas [documentation on the recent blockhashes sysvar][sdoc].
16//!
17//! [sdoc]: https://docs.atlaslabs.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 atlas_sdk_ids::sysvar::recent_blockhashes::{check_id, id, ID};
26use {
27    crate::Sysvar,
28    atlas_fee_calculator::FeeCalculator,
29    atlas_hash::Hash,
30    atlas_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
40impl_sysvar_id!(RecentBlockhashes);
41
42#[deprecated(
43    since = "1.9.0",
44    note = "Please do not use, will no longer be available in the future"
45)]
46#[repr(C)]
47#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
48#[derive(Clone, Debug, Default, PartialEq, Eq)]
49pub struct Entry {
50    pub blockhash: Hash,
51    pub fee_calculator: FeeCalculator,
52}
53impl Entry {
54    pub fn new(blockhash: &Hash, lamports_per_signature: u64) -> Self {
55        Self {
56            blockhash: *blockhash,
57            fee_calculator: FeeCalculator::new(lamports_per_signature),
58        }
59    }
60}
61
62#[deprecated(
63    since = "1.9.0",
64    note = "Please do not use, will no longer be available in the future"
65)]
66#[derive(Clone, Debug)]
67pub struct IterItem<'a>(pub u64, pub &'a Hash, pub u64);
68
69impl Eq for IterItem<'_> {}
70
71impl PartialEq for IterItem<'_> {
72    fn eq(&self, other: &Self) -> bool {
73        self.0 == other.0
74    }
75}
76
77impl Ord for IterItem<'_> {
78    fn cmp(&self, other: &Self) -> Ordering {
79        self.0.cmp(&other.0)
80    }
81}
82
83impl PartialOrd for IterItem<'_> {
84    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
85        Some(self.cmp(other))
86    }
87}
88
89/// Contains recent block hashes and fee calculators.
90///
91/// The entries are ordered by descending block height, so the first entry holds
92/// the most recent block hash, and the last entry holds an old block hash.
93#[deprecated(
94    since = "1.9.0",
95    note = "Please do not use, will no longer be available in the future"
96)]
97#[repr(C)]
98#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
99#[derive(Clone, Debug, PartialEq, Eq)]
100pub struct RecentBlockhashes(Vec<Entry>);
101
102impl Default for RecentBlockhashes {
103    fn default() -> Self {
104        Self(Vec::with_capacity(MAX_ENTRIES))
105    }
106}
107
108impl<'a> FromIterator<IterItem<'a>> for RecentBlockhashes {
109    fn from_iter<I>(iter: I) -> Self
110    where
111        I: IntoIterator<Item = IterItem<'a>>,
112    {
113        let mut new = Self::default();
114        for i in iter {
115            new.0.push(Entry::new(i.1, i.2))
116        }
117        new
118    }
119}
120
121// This is cherry-picked from HEAD of rust-lang's master (ref1) because it's
122// a nightly-only experimental API.
123// (binary_heap_into_iter_sorted [rustc issue #59278])
124// Remove this and use the standard API once BinaryHeap::into_iter_sorted (ref2)
125// is stabilized.
126// ref1: https://github.com/rust-lang/rust/blob/2f688ac602d50129388bb2a5519942049096cbff/src/liballoc/collections/binary_heap.rs#L1149
127// ref2: https://doc.rust-lang.org/std/collections/struct.BinaryHeap.html#into_iter_sorted.v
128
129#[derive(Clone, Debug)]
130pub struct IntoIterSorted<T> {
131    inner: BinaryHeap<T>,
132}
133impl<T> IntoIterSorted<T> {
134    pub fn new(binary_heap: BinaryHeap<T>) -> Self {
135        Self { inner: binary_heap }
136    }
137}
138
139impl<T: Ord> Iterator for IntoIterSorted<T> {
140    type Item = T;
141
142    #[inline]
143    fn next(&mut self) -> Option<T> {
144        self.inner.pop()
145    }
146
147    #[inline]
148    fn size_hint(&self) -> (usize, Option<usize>) {
149        let exact = self.inner.len();
150        (exact, Some(exact))
151    }
152}
153
154impl Sysvar for RecentBlockhashes {}
155
156#[cfg(feature = "bincode")]
157impl SysvarSerialize for RecentBlockhashes {
158    fn size_of() -> usize {
159        // hard-coded so that we don't have to construct an empty
160        6008 // golden, update if MAX_ENTRIES changes
161    }
162}
163
164impl Deref for RecentBlockhashes {
165    type Target = Vec<Entry>;
166    fn deref(&self) -> &Self::Target {
167        &self.0
168    }
169}
170
171#[cfg(test)]
172mod tests {
173    use {super::*, atlas_clock::MAX_PROCESSING_AGE};
174
175    #[test]
176    #[allow(clippy::assertions_on_constants)]
177    fn test_sysvar_can_hold_all_active_blockhashes() {
178        // Ensure we can still hold all of the active entries in `BlockhashQueue`
179        assert!(MAX_PROCESSING_AGE <= MAX_ENTRIES);
180    }
181
182    #[test]
183    fn test_size_of() {
184        let entry = Entry::new(&Hash::default(), 0);
185        assert_eq!(
186            bincode::serialized_size(&RecentBlockhashes(vec![entry; MAX_ENTRIES])).unwrap()
187                as usize,
188            RecentBlockhashes::size_of()
189        );
190    }
191}