1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//! A caching and checkpoint layer built upon semantically meaningful database
//! interfaces, providing interfaces and logics for managing accounts and global
//! statistics to the execution engine.

/// Contract Manager: Responsible for creating and deleting contract objects.
mod contract_manager;

/// Implements access functions for the basic fields (e.g., balance, nonce) of
/// `State`.
mod basic_fields;

/// Cache Layer: Implements a read-through write-back cache logic and provides
/// interfaces for reading and writing account data. It also handles the logic
/// for loading extension fields of an account.
mod cache_layer;

/// Checkpoints: Defines the account entry type within checkpoint layers and
/// implements checkpoint maintenance logic.
mod checkpoints;

/// Implements functions for the storage collateral of `State`.
mod collateral;

/// Implements functions for committing `State` changes to db.
mod commit;

/// Implements access functions global statistic variables of `State`.
mod global_statistics;

/// Implements functions for the PoS rewarding of `State`.
mod pos;

mod save;

/// Implements functions for the sponsorship mechanism of `State`.
mod sponsor;

/// Implements functions for the staking mechanism of `State`.
mod staking;

/// Implements access functions for the account storage entries of `State`.
mod storage_entry;

mod reward;

#[cfg(test)]
mod tests;

pub use self::{
    collateral::{initialize_cip107, settle_collateral_for_all},
    commit::StateCommitResult,
    pos::{distribute_pos_interest, update_pos_status},
    reward::initialize_cip137,
    sponsor::COMMISSION_PRIVILEGE_SPECIAL_KEY,
    staking::initialize_or_update_dao_voted_params,
};
#[cfg(test)]
pub use tests::{get_state_by_epoch_id, get_state_for_genesis_write};

use self::checkpoints::CheckpointLayer;
use super::{
    checkpoints::LazyDiscardedVec,
    global_stat::GlobalStat,
    overlay_account::{AccountEntry, OverlayAccount, RequireFields},
};
use crate::substate::Substate;
use cfx_statedb::{Result as DbResult, StateDbExt, StateDbGeneric as StateDb};
use cfx_types::AddressWithSpace;
use parking_lot::RwLock;
use std::collections::{BTreeSet, HashMap};

/// A caching and checkpoint layer built upon semantically meaningful database
/// interfaces, providing interfaces and logics for managing accounts and global
/// statistics to the execution engine.
pub struct State {
    /// The backend database
    pub(super) db: StateDb,

    /// Caches for the account entries
    ///
    /// WARNING: Don't delete cache entries outside of `State::commit`, unless
    /// you are familiar with checkpoint maintenance.
    cache: RwLock<HashMap<AddressWithSpace, AccountEntry>>,

    /// In-memory global statistic variables.
    // TODO: try not to make it special?
    global_stat: GlobalStat,

    /// Checkpoint layers for the account entries
    checkpoints: RwLock<LazyDiscardedVec<CheckpointLayer>>,
}

impl State {
    pub fn new(db: StateDb) -> DbResult<Self> {
        let initialized = db.is_initialized()?;

        let world_stat = if initialized {
            GlobalStat::loaded(&db)?
        } else {
            GlobalStat::assert_non_inited(&db)?;
            GlobalStat::new()
        };

        Ok(State {
            db,
            cache: Default::default(),
            checkpoints: Default::default(),
            global_stat: world_stat,
        })
    }

    pub fn prefetch_accounts(
        &self, addresses: BTreeSet<AddressWithSpace>, pool: &rayon::ThreadPool,
    ) -> DbResult<()> {
        use rayon::prelude::*;
        pool.install(|| {
            addresses
                .into_par_iter()
                .map(|addr| self.prefetch(&addr, RequireFields::Code))
        })
        .collect::<DbResult<()>>()
    }
}