solana_program_runtime/
accounts_data_meter.rs

1//! The accounts data space has a maximum size it is permitted to grow to.  This module contains
2//! the constants and types for tracking and metering the accounts data space during program
3//! runtime.
4
5/// The maximum allowed size, in bytes, of the accounts data
6/// 128 GB was chosen because it is the RAM amount listed under Hardware Recommendations on
7/// [Validator Requirements](https://docs.solana.com/running-validator/validator-reqs), and
8/// validators often put the ledger on a RAM disk (i.e. tmpfs).
9pub const MAX_ACCOUNTS_DATA_LEN: u64 = 128_000_000_000;
10
11/// Meter and track the amount of available accounts data space
12#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
13pub struct AccountsDataMeter {
14    /// The initial amount of accounts data space used (in bytes)
15    initial: u64,
16
17    /// The amount of accounts data space that has changed since `initial` (in bytes)
18    delta: i64,
19}
20
21impl AccountsDataMeter {
22    /// Make a new AccountsDataMeter
23    #[must_use]
24    pub fn new(initial_accounts_data_len: u64) -> Self {
25        Self {
26            initial: initial_accounts_data_len,
27            delta: 0,
28        }
29    }
30
31    /// Return the initial amount of accounts data space used (in bytes)
32    pub fn initial(&self) -> u64 {
33        self.initial
34    }
35
36    /// Return the amount of accounts data space that has changed (in bytes)
37    pub fn delta(&self) -> i64 {
38        self.delta
39    }
40
41    /// Return the current amount of accounts data space used (in bytes)
42    pub fn current(&self) -> u64 {
43        /// NOTE: Mixed integer ops currently not stable, so copying the impl.
44        /// * https://github.com/rust-lang/rust/issues/87840
45        /// * https://github.com/a1phyr/rust/blob/47edde1086412b36e9efd6098b191ec15a2a760a/library/core/src/num/uint_macros.rs#L1039-L1048
46        const fn saturating_add_signed(lhs: u64, rhs: i64) -> u64 {
47            let (res, overflow) = lhs.overflowing_add(rhs as u64);
48            if overflow == (rhs < 0) {
49                res
50            } else if overflow {
51                u64::MAX
52            } else {
53                u64::MIN
54            }
55        }
56        saturating_add_signed(self.initial, self.delta)
57    }
58
59    /// Adjust the space used by accounts data by `amount` (in bytes).
60    pub fn adjust_delta_unchecked(&mut self, amount: i64) {
61        self.delta = self.delta.saturating_add(amount);
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn test_new() {
71        let initial = 1234;
72        let accounts_data_meter = AccountsDataMeter::new(initial);
73        assert_eq!(accounts_data_meter.initial, initial);
74    }
75
76    #[test]
77    fn test_new_can_use_max_len() {
78        let _ = AccountsDataMeter::new(MAX_ACCOUNTS_DATA_LEN);
79    }
80}