cfxcore/consensus/consensus_graph/rpc_api/
state_provider.rs

1use crate::errors::{invalid_params_check, Result as CoreResult};
2
3use cfx_statedb::StateDb;
4use cfx_storage::{
5    state::StateTrait, state_manager::StateManagerTrait, StorageState,
6};
7use cfx_types::{Space, H256};
8
9use primitives::EpochNumber;
10
11use super::super::ConsensusGraph;
12
13impl ConsensusGraph {
14    pub fn get_storage_state_by_epoch_number(
15        &self, epoch_number: EpochNumber, rpc_param_name: &str,
16    ) -> CoreResult<StorageState> {
17        invalid_params_check(
18            rpc_param_name,
19            self.validate_stated_epoch(&epoch_number),
20        )?;
21        let height = invalid_params_check(
22            rpc_param_name,
23            self.get_height_from_epoch_number(epoch_number),
24        )?;
25        let hash =
26            self.inner.read().get_pivot_hash_from_epoch_number(height)?;
27        self.get_storage_state_by_height_and_hash(height, &hash)
28    }
29
30    pub fn get_eth_state_db_by_epoch_number(
31        &self, epoch_number: EpochNumber, rpc_param_name: &str,
32    ) -> CoreResult<StateDb> {
33        self.get_state_db_by_epoch_number_with_space(
34            epoch_number,
35            rpc_param_name,
36            Some(Space::Ethereum),
37        )
38    }
39
40    pub fn get_state_db_by_epoch_number(
41        &self, epoch_number: EpochNumber, rpc_param_name: &str,
42    ) -> CoreResult<StateDb> {
43        self.get_state_db_by_epoch_number_with_space(
44            epoch_number,
45            rpc_param_name,
46            None,
47        )
48    }
49
50    fn get_state_db_by_epoch_number_with_space(
51        &self, epoch_number: EpochNumber, rpc_param_name: &str,
52        space: Option<Space>,
53    ) -> CoreResult<StateDb> {
54        invalid_params_check(
55            rpc_param_name,
56            self.validate_stated_epoch(&epoch_number),
57        )?;
58        let height = invalid_params_check(
59            rpc_param_name,
60            self.get_height_from_epoch_number(epoch_number),
61        )?;
62        let hash =
63            self.inner.read().get_pivot_hash_from_epoch_number(height)?;
64        Ok(StateDb::new(
65            self.get_state_by_height_and_hash(height, &hash, space)?,
66        ))
67    }
68
69    fn get_storage_state_by_height_and_hash(
70        &self, height: u64, hash: &H256,
71    ) -> CoreResult<StorageState> {
72        // Keep the lock until we get the desired State, otherwise the State may
73        // expire.
74        let state_availability_boundary =
75            self.data_man.state_availability_boundary.read();
76        if !state_availability_boundary.check_availability(height, &hash) {
77            debug!(
78                "State for epoch (number={:?} hash={:?}) does not exist: out-of-bound {:?}",
79                height, hash, state_availability_boundary
80            );
81            bail!(format!(
82                "State for epoch (number={:?} hash={:?}) does not exist: out-of-bound {:?}",
83                height, hash, state_availability_boundary
84            ));
85        }
86        let maybe_state_readonly_index =
87            self.data_man.get_state_readonly_index(&hash).into();
88        let maybe_state = match maybe_state_readonly_index {
89            Some(state_readonly_index) => self
90                .data_man
91                .storage_manager
92                .get_state_no_commit_inner(
93                    state_readonly_index,
94                    /* try_open = */ true,
95                    true,
96                )
97                .map_err(|e| format!("Error to get state, err={:?}", e))?,
98            None => None,
99        };
100
101        let state = match maybe_state {
102            Some(state) => state,
103            None => {
104                bail!(format!(
105                    "State for epoch (number={:?} hash={:?}) does not exist",
106                    height, hash
107                ));
108            }
109        };
110
111        Ok(state)
112    }
113
114    fn get_state_by_height_and_hash(
115        &self, height: u64, hash: &H256, space: Option<Space>,
116    ) -> CoreResult<Box<dyn StateTrait>> {
117        // Keep the lock until we get the desired State, otherwise the State may
118        // expire.
119        let state_availability_boundary =
120            self.data_man.state_availability_boundary.read();
121        if !state_availability_boundary
122            .check_read_availability(height, &hash, space)
123        {
124            debug!(
125                "State for epoch (number={:?} hash={:?}) does not exist: out-of-bound {:?}",
126                height, hash, state_availability_boundary
127            );
128            bail!(format!(
129                "State for epoch (number={:?} hash={:?}) does not exist: out-of-bound {:?}",
130                height, hash, state_availability_boundary
131            ));
132        }
133        let maybe_state_readonly_index =
134            self.data_man.get_state_readonly_index(&hash).into();
135        let maybe_state = match maybe_state_readonly_index {
136            Some(state_readonly_index) => self
137                .data_man
138                .storage_manager
139                .get_state_no_commit(
140                    state_readonly_index,
141                    /* try_open = */ true,
142                    space,
143                )
144                .map_err(|e| format!("Error to get state, err={:?}", e))?,
145            None => None,
146        };
147
148        let state = match maybe_state {
149            Some(state) => state,
150            None => {
151                bail!(format!(
152                    "State for epoch (number={:?} hash={:?}) does not exist",
153                    height, hash
154                ));
155            }
156        };
157
158        Ok(state)
159    }
160}