solana_runtime/
rent_collector.rs

1//! Bank's wrapper around `RentCollector` to allow for overriding of some
2//! `SVMRentCollector` trait methods, which are otherwise implemented on
3//! `RentCollector` directly.
4//!
5//! Agave requires submission of logs and metrics during account rent state
6//! assessment, which is not included in the `RentCollector` implementation
7//! of the `SVMRentCollector` trait. This wrapper allows all `SVMRentCollector`
8//! methods to be passed through to the underlying `RentCollector`, except for
9//! those which require additional logging and metrics.
10
11use {
12    log::*,
13    solana_sdk::{
14        account::AccountSharedData,
15        clock::Epoch,
16        pubkey::Pubkey,
17        rent::{Rent, RentDue},
18        rent_collector::{CollectedInfo, RentCollector},
19        transaction::{Result, TransactionError},
20        transaction_context::IndexOfAccount,
21    },
22    solana_svm_rent_collector::{rent_state::RentState, svm_rent_collector::SVMRentCollector},
23};
24
25/// Wrapper around `RentCollector` to allow for overriding of some
26/// `SVMRentCollector` trait methods, which are otherwise implemented on
27/// `RentCollector` directly.
28///
29/// Overrides inject logging and metrics submission into the rent state
30/// assessment process.
31pub struct RentCollectorWithMetrics(RentCollector);
32
33impl RentCollectorWithMetrics {
34    pub fn new(rent_collector: RentCollector) -> Self {
35        Self(rent_collector)
36    }
37}
38
39impl SVMRentCollector for RentCollectorWithMetrics {
40    fn collect_rent(&self, address: &Pubkey, account: &mut AccountSharedData) -> CollectedInfo {
41        self.0.collect_rent(address, account)
42    }
43
44    fn get_rent(&self) -> &Rent {
45        self.0.get_rent()
46    }
47
48    fn get_rent_due(&self, lamports: u64, data_len: usize, account_rent_epoch: Epoch) -> RentDue {
49        self.0.get_rent_due(lamports, data_len, account_rent_epoch)
50    }
51
52    // Overriden to inject logging and metrics.
53    fn check_rent_state_with_account(
54        &self,
55        pre_rent_state: &RentState,
56        post_rent_state: &RentState,
57        address: &Pubkey,
58        account_state: &AccountSharedData,
59        account_index: IndexOfAccount,
60    ) -> Result<()> {
61        submit_rent_state_metrics(pre_rent_state, post_rent_state);
62        if !solana_sdk::incinerator::check_id(address)
63            && !self.transition_allowed(pre_rent_state, post_rent_state)
64        {
65            debug!(
66                "Account {} not rent exempt, state {:?}",
67                address, account_state,
68            );
69            let account_index = account_index as u8;
70            Err(TransactionError::InsufficientFundsForRent { account_index })
71        } else {
72            Ok(())
73        }
74    }
75}
76
77fn submit_rent_state_metrics(pre_rent_state: &RentState, post_rent_state: &RentState) {
78    match (pre_rent_state, post_rent_state) {
79        (&RentState::Uninitialized, &RentState::RentPaying { .. }) => {
80            inc_new_counter_info!("rent_paying_err-new_account", 1);
81        }
82        (&RentState::RentPaying { .. }, &RentState::RentPaying { .. }) => {
83            inc_new_counter_info!("rent_paying_ok-legacy", 1);
84        }
85        (_, &RentState::RentPaying { .. }) => {
86            inc_new_counter_info!("rent_paying_err-other", 1);
87        }
88        _ => {}
89    }
90}