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}