light_compressible/rent/
config.rs

1use aligned_sized::aligned_sized;
2use bytemuck::{Pod, Zeroable};
3use light_zero_copy::{ZeroCopy, ZeroCopyMut};
4
5use crate::{AnchorDeserialize, AnchorSerialize};
6pub const COMPRESSION_COST: u16 = 10_000;
7pub const COMPRESSION_INCENTIVE: u16 = 1000;
8
9pub const BASE_RENT: u16 = 128; // TODO: multiply by 10
10pub const RENT_PER_BYTE: u8 = 1; // TODO: multiply by 10
11                                 // Epoch duration: 1.5 hours, 90 minutes * 60 seconds / 0.4 seconds per slot = 13,500 slots per epoch
12pub const SLOTS_PER_EPOCH: u64 = 13500; // TODO: multiply by 10
13
14/// Trait for accessing rent configuration parameters.
15///
16/// This trait allows both owned `RentConfig` and zero-copy versions
17/// (`ZRentConfig`, `ZRentConfigMut`) to be used interchangeably with
18/// `AccountRentState` methods.
19pub trait RentConfigTrait {
20    /// Get the base rent value
21    fn base_rent(&self) -> u64;
22
23    /// Get the compression cost
24    fn compression_cost(&self) -> u64;
25
26    /// Get lamports per byte per epoch
27    fn lamports_per_byte_per_epoch(&self) -> u64;
28
29    /// Get maximum funded epochs
30    fn max_funded_epochs(&self) -> u64;
31
32    /// Get maximum top-up amount per write operation
33    fn max_top_up(&self) -> u64;
34
35    /// Calculate rent per epoch for a given number of bytes
36    #[inline(always)]
37    fn rent_curve_per_epoch(&self, num_bytes: u64) -> u64 {
38        self.base_rent() + num_bytes * self.lamports_per_byte_per_epoch()
39    }
40
41    /// Calculate total rent for given bytes and epochs
42    #[inline(always)]
43    fn get_rent(&self, num_bytes: u64, epochs: u64) -> u64 {
44        self.rent_curve_per_epoch(num_bytes) * epochs
45    }
46
47    /// Calculate total rent including compression cost
48    #[inline(always)]
49    fn get_rent_with_compression_cost(&self, num_bytes: u64, epochs: u64) -> u64 {
50        self.get_rent(num_bytes, epochs) + self.compression_cost()
51    }
52}
53
54/// Rent function parameters,
55/// used to calculate whether the account is compressible.
56#[derive(
57    Debug,
58    Clone,
59    Hash,
60    Copy,
61    PartialEq,
62    Eq,
63    AnchorSerialize,
64    AnchorDeserialize,
65    ZeroCopy,
66    ZeroCopyMut,
67    Pod,
68    Zeroable,
69)]
70#[repr(C)]
71#[aligned_sized]
72pub struct RentConfig {
73    /// Base rent constant: rent = base_rent + num_bytes * lamports_per_byte_per_epoch
74    pub base_rent: u16,
75    pub compression_cost: u16,
76    pub lamports_per_byte_per_epoch: u8,
77    pub max_funded_epochs: u8, // once the account is funded for max_funded_epochs top up per write is not executed
78    /// Maximum lamports that can be charged per top-up operation.
79    /// Protects against griefing by accounts with high lamports_per_write.
80    pub max_top_up: u16,
81}
82
83impl Default for RentConfig {
84    fn default() -> Self {
85        Self {
86            base_rent: BASE_RENT,
87            compression_cost: COMPRESSION_COST + COMPRESSION_INCENTIVE,
88            lamports_per_byte_per_epoch: RENT_PER_BYTE,
89            max_funded_epochs: 2, // once the account is funded for max_funded_epochs top up per write is not executed
90            max_top_up: 12416,    // 48h rent for ctoken accounts of size 260 bytes
91        }
92    }
93}
94
95impl RentConfigTrait for RentConfig {
96    #[inline(always)]
97    fn base_rent(&self) -> u64 {
98        self.base_rent as u64
99    }
100
101    #[inline(always)]
102    fn compression_cost(&self) -> u64 {
103        self.compression_cost as u64
104    }
105
106    #[inline(always)]
107    fn lamports_per_byte_per_epoch(&self) -> u64 {
108        self.lamports_per_byte_per_epoch as u64
109    }
110
111    #[inline(always)]
112    fn max_funded_epochs(&self) -> u64 {
113        self.max_funded_epochs as u64
114    }
115
116    #[inline(always)]
117    fn max_top_up(&self) -> u64 {
118        self.max_top_up as u64
119    }
120}
121
122impl RentConfig {
123    pub fn rent_curve_per_epoch(&self, num_bytes: u64) -> u64 {
124        RentConfigTrait::rent_curve_per_epoch(self, num_bytes)
125    }
126    pub fn get_rent(&self, num_bytes: u64, epochs: u64) -> u64 {
127        RentConfigTrait::get_rent(self, num_bytes, epochs)
128    }
129    pub fn get_rent_with_compression_cost(&self, num_bytes: u64, epochs: u64) -> u64 {
130        RentConfigTrait::get_rent_with_compression_cost(self, num_bytes, epochs)
131    }
132}
133
134// Implement trait for zero-copy immutable reference
135impl RentConfigTrait for ZRentConfig<'_> {
136    #[inline(always)]
137    fn base_rent(&self) -> u64 {
138        self.base_rent.into()
139    }
140
141    #[inline(always)]
142    fn compression_cost(&self) -> u64 {
143        self.compression_cost.into()
144    }
145
146    #[inline(always)]
147    fn lamports_per_byte_per_epoch(&self) -> u64 {
148        self.lamports_per_byte_per_epoch as u64
149    }
150
151    #[inline(always)]
152    fn max_funded_epochs(&self) -> u64 {
153        self.max_funded_epochs as u64
154    }
155
156    #[inline(always)]
157    fn max_top_up(&self) -> u64 {
158        self.max_top_up.into()
159    }
160}
161
162// Implement trait for zero-copy mutable reference
163impl RentConfigTrait for ZRentConfigMut<'_> {
164    #[inline(always)]
165    fn base_rent(&self) -> u64 {
166        self.base_rent.into()
167    }
168
169    #[inline(always)]
170    fn compression_cost(&self) -> u64 {
171        self.compression_cost.into()
172    }
173
174    #[inline(always)]
175    fn lamports_per_byte_per_epoch(&self) -> u64 {
176        self.lamports_per_byte_per_epoch as u64
177    }
178
179    #[inline(always)]
180    fn max_funded_epochs(&self) -> u64 {
181        self.max_funded_epochs as u64
182    }
183
184    #[inline(always)]
185    fn max_top_up(&self) -> u64 {
186        self.max_top_up.into()
187    }
188}
189
190impl ZRentConfigMut<'_> {
191    /// Sets all fields from a RentConfig instance, handling zero-copy type conversions
192    pub fn set(&mut self, config: &RentConfig) {
193        self.base_rent = config.base_rent.into();
194        self.compression_cost = config.compression_cost.into();
195        self.lamports_per_byte_per_epoch = config.lamports_per_byte_per_epoch;
196        self.max_funded_epochs = config.max_funded_epochs;
197        self.max_top_up = config.max_top_up.into();
198    }
199}