cfx_executor/state/state_object/
warm.rs

1use crate::try_loaded;
2use cfx_statedb::Result as DbResult;
3use cfx_types::{AddressSpaceUtil, AddressWithSpace, Space, H256};
4use cfx_vm_types::ActionParams;
5use primitives::AccessListItem;
6use std::collections::{HashMap, HashSet};
7
8use super::State;
9
10impl State {
11    pub fn is_warm_account(&self, address: &AddressWithSpace) -> bool {
12        if self
13            .tx_access_list
14            .as_ref()
15            .map_or(false, |x| x.contains_key(address))
16        {
17            return true;
18        }
19        self.cache.read().get(address).map_or(false, |x| x.warm)
20    }
21
22    pub fn is_warm_storage_entry(
23        &self, address: &AddressWithSpace, key: &H256,
24    ) -> DbResult<bool> {
25        if self.is_warm_storage_entry_in_access_list(address, key) {
26            return Ok(true);
27        }
28
29        let acc = try_loaded!(self.read_account_lock(address));
30        Ok(acc.is_warm_storage_entry(&key[..]))
31    }
32
33    fn is_warm_storage_entry_in_access_list(
34        &self, address: &AddressWithSpace, key: &H256,
35    ) -> bool {
36        let Some(access_list) = self.tx_access_list.as_ref() else {
37            return false;
38        };
39        let Some(account) = access_list.get(address) else {
40            return false;
41        };
42        account.contains(key)
43    }
44
45    /// Pre-warms the addresses and storage keys carried by the transaction's
46    /// access list.
47    ///
48    /// EIP-2930 permits the same address to appear in more than one entry, in
49    /// which case the warmed storage keys are the union over all of its
50    /// entries. Before CIP-176 a later entry replaced the storage keys
51    /// recorded by an earlier one, leaving the earlier keys cold even though
52    /// the transaction was charged for them.
53    pub fn set_tx_access_list(
54        &mut self, space: Space, access_list: &[AccessListItem], cip176: bool,
55    ) {
56        let access_list = if cip176 {
57            let mut warmed: HashMap<AddressWithSpace, HashSet<H256>> =
58                HashMap::new();
59            for x in access_list {
60                warmed
61                    .entry(x.address.with_space(space))
62                    .or_default()
63                    .extend(x.storage_keys.iter().cloned());
64            }
65            warmed
66        } else {
67            access_list
68                .iter()
69                .map(|x| {
70                    (
71                        x.address.with_space(space),
72                        x.storage_keys.iter().cloned().collect(),
73                    )
74                })
75                .collect()
76        };
77
78        self.tx_access_list = Some(access_list);
79    }
80
81    pub fn touch_tx_addresses(&self, params: &ActionParams) -> DbResult<()> {
82        self.touch(&params.address.with_space(params.space))?;
83        self.touch(&params.sender.with_space(params.space))?;
84        Ok(())
85    }
86
87    pub fn clear_tx_access_list(&mut self) { self.tx_access_list = None; }
88
89    pub fn update_state_post_tx_execution(
90        &mut self, retain_transient_storage: bool,
91    ) {
92        self.clear_tx_access_list();
93        self.commit_cache(retain_transient_storage);
94    }
95}