cfx_executor/state/state_object/
mod.rs

1//! A caching and checkpoint layer built upon semantically meaningful database
2//! interfaces, providing interfaces and logics for managing accounts and global
3//! statistics to the execution engine.
4
5/// Contract Manager: Responsible for creating and deleting contract objects.
6mod contract_manager;
7
8/// Implements access functions for the basic fields (e.g., balance, nonce) of
9/// `State`.
10mod basic_fields;
11
12/// Cache Layer: Implements a read-through write-back cache logic and provides
13/// interfaces for reading and writing account data. It also handles the logic
14/// for loading extension fields of an account.
15mod cache_layer;
16
17/// Checkpoints: Defines the account entry type within checkpoint layers and
18/// implements checkpoint maintenance logic.
19mod checkpoints;
20
21/// Implements functions for the storage collateral of `State`.
22mod collateral;
23
24/// Implements functions for committing `State` changes to db.
25mod commit;
26
27/// Implements access functions global statistic variables of `State`.
28mod global_statistics;
29
30mod warm;
31
32/// Implements functions for the PoS rewarding of `State`.
33mod pos;
34
35mod save;
36
37/// Implements functions for the sponsorship mechanism of `State`.
38mod sponsor;
39
40/// Implements functions for the staking mechanism of `State`.
41mod staking;
42
43/// Implements access functions for the account storage entries of `State`.
44mod storage_entry;
45
46mod reward;
47
48mod state_override;
49
50#[cfg(test)]
51mod tests;
52
53pub use self::{
54    collateral::{initialize_cip107, settle_collateral_for_all},
55    commit::StateCommitResult,
56    pos::{distribute_pos_interest, update_pos_status},
57    reward::initialize_cip137,
58    sponsor::COMMISSION_PRIVILEGE_SPECIAL_KEY,
59    staking::initialize_or_update_dao_voted_params,
60};
61#[cfg(test)]
62pub use tests::{get_state_by_epoch_id, get_state_for_genesis_write};
63
64use self::checkpoints::CheckpointLayer;
65use super::{
66    checkpoints::LazyDiscardedVec,
67    global_stat::GlobalStat,
68    overlay_account::{
69        AccountEntry, AccountEntryWithWarm, OverlayAccount, RequireFields,
70    },
71};
72use crate::substate::Substate;
73use cfx_statedb::{Result as DbResult, StateDbExt, StateDbGeneric as StateDb};
74use cfx_types::{AddressWithSpace, H256};
75use parking_lot::RwLock;
76use std::collections::{BTreeSet, HashMap, HashSet};
77
78/// A caching and checkpoint layer built upon semantically meaningful database
79/// interfaces, providing interfaces and logics for managing accounts and global
80/// statistics to the execution engine.
81pub struct State {
82    /// The backend database
83    pub(super) db: StateDb,
84
85    /// Caches for the account entries
86    ///
87    /// WARNING: Don't delete cache entries outside of `State::commit`, unless
88    /// you are familiar with checkpoint maintenance.
89    pub cache: RwLock<HashMap<AddressWithSpace, AccountEntryWithWarm>>,
90
91    pub committed_cache: HashMap<AddressWithSpace, AccountEntry>,
92    tx_access_list: Option<HashMap<AddressWithSpace, HashSet<H256>>>,
93
94    /// In-memory global statistic variables.
95    // TODO: try not to make it special?
96    global_stat: GlobalStat,
97
98    /// Checkpoint layers for the account entries
99    // TODO: it seems `RwLock` is not necessary here. But we need to change the
100    // signature of `write_account` from `&self` to `&mut self` first
101    checkpoints: RwLock<LazyDiscardedVec<CheckpointLayer>>,
102}
103
104impl State {
105    pub fn new(db: StateDb) -> DbResult<Self> {
106        let initialized = db.is_initialized()?;
107
108        let world_stat = if initialized {
109            GlobalStat::loaded(&db)?
110        } else {
111            GlobalStat::assert_non_inited(&db)?;
112            GlobalStat::new()
113        };
114
115        Ok(State {
116            db,
117            cache: Default::default(),
118            committed_cache: Default::default(),
119            checkpoints: Default::default(),
120            tx_access_list: None,
121            global_stat: world_stat,
122        })
123    }
124
125    pub fn prefetch_accounts(
126        &mut self, addresses: BTreeSet<AddressWithSpace>,
127        pool: &rayon::ThreadPool,
128    ) -> DbResult<()> {
129        use rayon::prelude::*;
130
131        pool.install(|| {
132            addresses
133                .into_par_iter()
134                .map(|addr| self.prefetch(&addr, RequireFields::Code))
135        })
136        .collect::<DbResult<()>>()?;
137
138        assert!(self.committed_cache.is_empty());
139        self.commit_cache(false);
140        Ok(())
141    }
142}