@@ -18,6 +18,15 @@ pub const DEFAULT_LAMPORTS_PER_BYTE_YEAR: u64 = 1_000_000_000 / 100 * 365 / (102
18
18
/// account to be rent exempt.
19
19
pub const DEFAULT_EXEMPTION_THRESHOLD : f64 = 2.0 ;
20
20
21
+ /// Default amount of time (in years) the balance has to include rent for the
22
+ /// account to be rent exempt as a `u64`.
23
+ const DEFAULT_EXEMPTION_THRESHOLD_AS_U64 : u64 = 2 ;
24
+
25
+ /// The `u64` representation of the default exemption threshold.
26
+ ///
27
+ /// This is used to check whether the `f64` value can be safely cast to a `u64`.
28
+ const F64_EXEMPTION_THRESHOLD_AS_U64 : u64 = 4611686018427387904 ;
29
+
21
30
/// Default percentage of collected rent that is burned.
22
31
///
23
32
/// Valid values are in the range [0, 100]. The remaining percentage is
@@ -44,27 +53,29 @@ pub struct Rent {
44
53
pub burn_percent : u8 ,
45
54
}
46
55
47
- /// Calculates the rent for a given number of bytes and duration
48
- ///
49
- /// # Arguments
50
- ///
51
- /// * `bytes` - The number of bytes to calculate rent for
52
- /// * `years` - The number of years to calculate rent for
53
- ///
54
- /// # Returns
55
- ///
56
- /// The total rent in lamports
57
56
impl Rent {
57
+ /// Return a `Rent` from the given bytes.
58
+ ///
59
+ /// # Safety
60
+ ///
61
+ /// The caller must ensure that `bytes` contains a valid representation of `Rent`.
62
+ #[ inline]
63
+ pub unsafe fn from_bytes ( bytes : & [ u8 ] ) -> & Self {
64
+ & * ( bytes. as_ptr ( ) as * const Rent )
65
+ }
66
+
58
67
/// Calculate how much rent to burn from the collected rent.
59
68
///
60
69
/// The first value returned is the amount burned. The second is the amount
61
70
/// to distribute to validators.
71
+ #[ inline]
62
72
pub fn calculate_burn ( & self , rent_collected : u64 ) -> ( u64 , u64 ) {
63
73
let burned_portion = ( rent_collected * u64:: from ( self . burn_percent ) ) / 100 ;
64
74
( burned_portion, rent_collected - burned_portion)
65
75
}
66
76
67
77
/// Rent due on account's data length with balance.
78
+ #[ inline]
68
79
pub fn due ( & self , balance : u64 , data_len : usize , years_elapsed : f64 ) -> RentDue {
69
80
if self . is_exempt ( balance, data_len) {
70
81
RentDue :: Exempt
@@ -74,6 +85,7 @@ impl Rent {
74
85
}
75
86
76
87
/// Rent due for account that is known to be not exempt.
88
+ #[ inline]
77
89
pub fn due_amount ( & self , data_len : usize , years_elapsed : f64 ) -> u64 {
78
90
let actual_data_len = data_len as u64 + ACCOUNT_STORAGE_OVERHEAD ;
79
91
let lamports_per_year = self . lamports_per_byte_year * actual_data_len;
@@ -82,17 +94,27 @@ impl Rent {
82
94
83
95
/// Calculates the minimum balance for rent exemption.
84
96
///
97
+ /// This method avoids floating-point operations when the `exemption_threshold`
98
+ /// is the default value.
99
+ ///
85
100
/// # Arguments
86
101
///
87
102
/// * `data_len` - The number of bytes in the account
88
103
///
89
104
/// # Returns
90
105
///
91
106
/// The minimum balance in lamports for rent exemption.
107
+ #[ inline]
92
108
pub fn minimum_balance ( & self , data_len : usize ) -> u64 {
93
109
let bytes = data_len as u64 ;
94
- ( ( ( ACCOUNT_STORAGE_OVERHEAD + bytes) * self . lamports_per_byte_year ) as f64
95
- * self . exemption_threshold ) as u64
110
+
111
+ if self . is_default_rent_threshold ( ) {
112
+ ( ( ACCOUNT_STORAGE_OVERHEAD + bytes) * self . lamports_per_byte_year )
113
+ * DEFAULT_EXEMPTION_THRESHOLD_AS_U64
114
+ } else {
115
+ ( ( ( ACCOUNT_STORAGE_OVERHEAD + bytes) * self . lamports_per_byte_year ) as f64
116
+ * self . exemption_threshold ) as u64
117
+ }
96
118
}
97
119
98
120
/// Determines if an account can be considered rent exempt.
@@ -105,9 +127,19 @@ impl Rent {
105
127
/// # Returns
106
128
///
107
129
/// `true`` if the account is rent exempt, `false`` otherwise.
130
+ #[ inline]
108
131
pub fn is_exempt ( & self , lamports : u64 , data_len : usize ) -> bool {
109
132
lamports >= self . minimum_balance ( data_len)
110
133
}
134
+
135
+ /// Determines if the `exemption_threshold` is the default value.
136
+ ///
137
+ /// This is used to check whether the `f64` value can be safely cast to a `u64`
138
+ /// to avoid floating-point operations.
139
+ #[ inline]
140
+ fn is_default_rent_threshold ( & self ) -> bool {
141
+ u64:: from_le_bytes ( self . exemption_threshold . to_le_bytes ( ) ) == F64_EXEMPTION_THRESHOLD_AS_U64
142
+ }
111
143
}
112
144
113
145
impl Sysvar for Rent {
@@ -140,3 +172,39 @@ impl RentDue {
140
172
}
141
173
}
142
174
}
175
+
176
+ #[ cfg( test) ]
177
+ mod tests {
178
+ use crate :: sysvars:: rent:: {
179
+ ACCOUNT_STORAGE_OVERHEAD , DEFAULT_BURN_PERCENT , DEFAULT_EXEMPTION_THRESHOLD ,
180
+ DEFAULT_LAMPORTS_PER_BYTE_YEAR ,
181
+ } ;
182
+
183
+ #[ test]
184
+ pub fn test_minimum_balance ( ) {
185
+ let mut rent = super :: Rent {
186
+ lamports_per_byte_year : DEFAULT_LAMPORTS_PER_BYTE_YEAR ,
187
+ exemption_threshold : DEFAULT_EXEMPTION_THRESHOLD ,
188
+ burn_percent : DEFAULT_BURN_PERCENT ,
189
+ } ;
190
+
191
+ // Using the default exemption threshold.
192
+
193
+ let balance = rent. minimum_balance ( 100 ) ;
194
+ let calculated = ( ( ( ACCOUNT_STORAGE_OVERHEAD + 100 ) * rent. lamports_per_byte_year ) as f64
195
+ * rent. exemption_threshold ) as u64 ;
196
+
197
+ assert ! ( calculated > 0 ) ;
198
+ assert_eq ! ( balance, calculated) ;
199
+
200
+ // Using a different exemption threshold.
201
+ rent. exemption_threshold = 0.5 ;
202
+
203
+ let balance = rent. minimum_balance ( 100 ) ;
204
+ let calculated = ( ( ( ACCOUNT_STORAGE_OVERHEAD + 100 ) * rent. lamports_per_byte_year ) as f64
205
+ * rent. exemption_threshold ) as u64 ;
206
+
207
+ assert ! ( calculated > 0 ) ;
208
+ assert_eq ! ( balance, calculated) ;
209
+ }
210
+ }
0 commit comments