solana_rent/
lib.rs

1//! Configuration for network [rent].
2//!
3//! [rent]: https://docs.solanalabs.com/implemented-proposals/rent
4
5#![allow(clippy::arithmetic_side_effects)]
6#![no_std]
7#![cfg_attr(docsrs, feature(doc_cfg))]
8#![cfg_attr(feature = "frozen-abi", feature(min_specialization))]
9#[cfg(feature = "frozen-abi")]
10extern crate std;
11
12#[cfg(feature = "sysvar")]
13pub mod sysvar;
14
15use solana_sdk_macro::CloneZeroed;
16
17// inlined to avoid solana_clock dep
18const DEFAULT_SLOTS_PER_EPOCH: u64 = 432_000;
19#[cfg(test)]
20static_assertions::const_assert_eq!(
21    DEFAULT_SLOTS_PER_EPOCH,
22    solana_clock::DEFAULT_SLOTS_PER_EPOCH
23);
24
25/// Configuration of network rent.
26#[repr(C)]
27#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))]
28#[cfg_attr(
29    feature = "serde",
30    derive(serde_derive::Deserialize, serde_derive::Serialize)
31)]
32#[derive(PartialEq, CloneZeroed, Debug)]
33pub struct Rent {
34    /// Rental rate in lamports/byte-year.
35    #[deprecated(
36        since = "3.1.0",
37        note = "Field will be renamed to `lamports_per_byte` in v4, use `Rent::new_with_lamports_per_byte` to create, and `Rent::minimum_balance` or `Rent::is_exempt`"
38    )]
39    pub lamports_per_byte_year: u64,
40
41    /// Amount of time (in years) a balance must include rent for the account to
42    /// be rent exempt.
43    #[deprecated(
44        since = "3.1.0",
45        note = "Exemption threshold will be set to 1f64 with SIMD-0194 and should no longer be used"
46    )]
47    pub exemption_threshold: f64,
48
49    /// The percentage of collected rent that is burned.
50    ///
51    /// Valid values are in the range [0, 100]. The remaining percentage is
52    /// distributed to validators.
53    #[deprecated(
54        since = "3.1.0",
55        note = "The concept of rent no longer exists, only rent-exemption"
56    )]
57    pub burn_percent: u8,
58}
59
60/// Default rental rate in lamports/byte-year.
61///
62/// This calculation is based on:
63/// - 10^9 lamports per SOL
64/// - $1 per SOL
65/// - $0.01 per megabyte day
66/// - $3.65 per megabyte year
67#[deprecated(
68    since = "3.1.0",
69    note = "The concept of rent no longer exists, only rent-exemption. Use `DEFAULT_LAMPORTS_PER_BYTE` instead"
70)]
71pub const DEFAULT_LAMPORTS_PER_BYTE_YEAR: u64 = 1_000_000_000 / 100 * 365 / (1024 * 1024);
72
73/// Default rental rate in lamports/byte.
74///
75/// This calculation is based on:
76/// - 10^9 lamports per SOL
77/// - $1 per SOL
78/// - $0.01 per megabyte day
79/// - $7.30 per megabyte
80pub const DEFAULT_LAMPORTS_PER_BYTE: u64 = 6_960;
81
82/// Default amount of time (in years) the balance has to include rent for the
83/// account to be rent exempt.
84#[deprecated(
85    since = "3.1.0",
86    note = "The concept of rent no longer exists, only rent-exemption"
87)]
88pub const DEFAULT_EXEMPTION_THRESHOLD: f64 = 2.0;
89
90/// Default percentage of collected rent that is burned.
91///
92/// Valid values are in the range [0, 100]. The remaining percentage is
93/// distributed to validators.
94#[deprecated(
95    since = "3.1.0",
96    note = "The concept of rent no longer exists, only rent-exemption"
97)]
98pub const DEFAULT_BURN_PERCENT: u8 = 50;
99
100/// Account storage overhead for calculation of base rent.
101///
102/// This is the number of bytes required to store an account with no data. It is
103/// added to an accounts data length when calculating [`Rent::minimum_balance`].
104pub const ACCOUNT_STORAGE_OVERHEAD: u64 = 128;
105
106impl Default for Rent {
107    #[allow(deprecated)]
108    fn default() -> Self {
109        Self {
110            lamports_per_byte_year: DEFAULT_LAMPORTS_PER_BYTE_YEAR,
111            exemption_threshold: DEFAULT_EXEMPTION_THRESHOLD,
112            burn_percent: DEFAULT_BURN_PERCENT,
113        }
114    }
115}
116
117impl Rent {
118    /// Calculate how much rent to burn from the collected rent.
119    ///
120    /// The first value returned is the amount burned. The second is the amount
121    /// to distribute to validators.
122    #[deprecated(
123        since = "3.1.0",
124        note = "The concept of rent no longer exists, only rent-exemption"
125    )]
126    #[allow(deprecated)]
127    pub fn calculate_burn(&self, rent_collected: u64) -> (u64, u64) {
128        let burned_portion = (rent_collected * u64::from(self.burn_percent)) / 100;
129        (burned_portion, rent_collected - burned_portion)
130    }
131
132    /// Minimum balance due for rent-exemption of a given account data size.
133    #[allow(deprecated)]
134    pub fn minimum_balance(&self, data_len: usize) -> u64 {
135        let bytes = data_len as u64;
136        (((ACCOUNT_STORAGE_OVERHEAD + bytes) * self.lamports_per_byte_year) as f64
137            * self.exemption_threshold) as u64
138    }
139
140    /// Whether a given balance and data length would be exempt.
141    pub fn is_exempt(&self, balance: u64, data_len: usize) -> bool {
142        balance >= self.minimum_balance(data_len)
143    }
144
145    /// Rent due on account's data length with balance.
146    #[deprecated(
147        since = "3.1.0",
148        note = "The concept of rent no longer exists, only rent-exemption"
149    )]
150    #[allow(deprecated)]
151    pub fn due(&self, balance: u64, data_len: usize, years_elapsed: f64) -> RentDue {
152        if self.is_exempt(balance, data_len) {
153            RentDue::Exempt
154        } else {
155            RentDue::Paying(self.due_amount(data_len, years_elapsed))
156        }
157    }
158
159    /// Rent due for account that is known to be not exempt.
160    #[deprecated(
161        since = "3.1.0",
162        note = "The concept of rent no longer exists, only rent-exemption"
163    )]
164    #[allow(deprecated)]
165    pub fn due_amount(&self, data_len: usize, years_elapsed: f64) -> u64 {
166        let actual_data_len = data_len as u64 + ACCOUNT_STORAGE_OVERHEAD;
167        let lamports_per_year = self.lamports_per_byte_year * actual_data_len;
168        (lamports_per_year as f64 * years_elapsed) as u64
169    }
170
171    /// Creates a `Rent` that charges no lamports.
172    ///
173    /// This is used for testing.
174    #[allow(deprecated)]
175    pub fn free() -> Self {
176        Self {
177            lamports_per_byte_year: 0,
178            ..Rent::default()
179        }
180    }
181
182    /// Creates a `Rent` that is scaled based on the number of slots in an epoch.
183    ///
184    /// This is used for testing.
185    #[deprecated(
186        since = "3.1.0",
187        note = "The concept of rent no longer exists, only rent-exemption, use `Rent::with_lamports_per_byte`"
188    )]
189    #[allow(deprecated)]
190    pub fn with_slots_per_epoch(slots_per_epoch: u64) -> Self {
191        let ratio = slots_per_epoch as f64 / DEFAULT_SLOTS_PER_EPOCH as f64;
192        let exemption_threshold = DEFAULT_EXEMPTION_THRESHOLD * ratio;
193        let lamports_per_byte_year = (DEFAULT_LAMPORTS_PER_BYTE_YEAR as f64 / ratio) as u64;
194        Self {
195            lamports_per_byte_year,
196            exemption_threshold,
197            ..Self::default()
198        }
199    }
200
201    /// Creates a `Rent` with lamports per byte
202    #[allow(deprecated)]
203    pub fn with_lamports_per_byte(lamports_per_byte: u64) -> Self {
204        Self {
205            lamports_per_byte_year: lamports_per_byte,
206            exemption_threshold: 1.0,
207            ..Self::default()
208        }
209    }
210}
211
212/// The return value of [`Rent::due`].
213#[deprecated(
214    since = "3.1.0",
215    note = "The concept of rent no longer exists, only rent-exemption"
216)]
217#[derive(Debug, Copy, Clone, Eq, PartialEq)]
218pub enum RentDue {
219    /// Used to indicate the account is rent exempt.
220    Exempt,
221    /// The account owes this much rent.
222    Paying(u64),
223}
224
225#[allow(deprecated)]
226impl RentDue {
227    /// Return the lamports due for rent.
228    pub fn lamports(&self) -> u64 {
229        match self {
230            RentDue::Exempt => 0,
231            RentDue::Paying(x) => *x,
232        }
233    }
234
235    /// Return 'true' if rent exempt.
236    pub fn is_exempt(&self) -> bool {
237        match self {
238            RentDue::Exempt => true,
239            RentDue::Paying(_) => false,
240        }
241    }
242}
243
244#[cfg(test)]
245mod tests {
246    use super::*;
247
248    #[test]
249    #[allow(deprecated)]
250    fn test_due() {
251        let default_rent = Rent::default();
252
253        assert_eq!(
254            default_rent.due(0, 2, 1.2),
255            RentDue::Paying(
256                (((2 + ACCOUNT_STORAGE_OVERHEAD) * DEFAULT_LAMPORTS_PER_BYTE_YEAR) as f64 * 1.2)
257                    as u64
258            ),
259        );
260        assert_eq!(
261            default_rent.due(
262                (((2 + ACCOUNT_STORAGE_OVERHEAD) * DEFAULT_LAMPORTS_PER_BYTE_YEAR) as f64
263                    * DEFAULT_EXEMPTION_THRESHOLD) as u64,
264                2,
265                1.2
266            ),
267            RentDue::Exempt,
268        );
269
270        let custom_rent = Rent {
271            lamports_per_byte_year: 5,
272            exemption_threshold: 2.5,
273            ..Rent::default()
274        };
275
276        assert_eq!(
277            custom_rent.due(0, 2, 1.2),
278            RentDue::Paying(
279                (((2 + ACCOUNT_STORAGE_OVERHEAD) * custom_rent.lamports_per_byte_year) as f64 * 1.2)
280                    as u64,
281            )
282        );
283
284        assert_eq!(
285            custom_rent.due(
286                (((2 + ACCOUNT_STORAGE_OVERHEAD) * custom_rent.lamports_per_byte_year) as f64
287                    * custom_rent.exemption_threshold) as u64,
288                2,
289                1.2
290            ),
291            RentDue::Exempt
292        );
293    }
294
295    #[test]
296    #[allow(deprecated)]
297    fn test_rent_due_lamports() {
298        assert_eq!(RentDue::Exempt.lamports(), 0);
299
300        let amount = 123;
301        assert_eq!(RentDue::Paying(amount).lamports(), amount);
302    }
303
304    #[test]
305    #[allow(deprecated)]
306    fn test_rent_due_is_exempt() {
307        assert!(RentDue::Exempt.is_exempt());
308        assert!(!RentDue::Paying(0).is_exempt());
309    }
310
311    #[test]
312    #[allow(deprecated)]
313    fn test_clone() {
314        let rent = Rent {
315            lamports_per_byte_year: 1,
316            exemption_threshold: 2.2,
317            burn_percent: 3,
318        };
319        #[allow(clippy::clone_on_copy)]
320        let cloned_rent = rent.clone();
321        assert_eq!(cloned_rent, rent);
322    }
323}