cfxcore/consensus/consensus_graph/
mod.rs

1pub(super) mod best_info_provider;
2pub(super) mod mining_api;
3pub(super) mod onchain_blocks_provider;
4pub(super) mod rpc_api;
5pub(super) mod sync_graph_api;
6
7use self::best_info_provider::BestInformation;
8
9use super::{
10    consensus_inner::{
11        confirmation_meter::ConfirmationMeter,
12        consensus_executor::ConsensusExecutor,
13        consensus_new_block_handler::ConsensusNewBlockHandler,
14    },
15    pivot_hint::PivotHint,
16};
17pub use crate::consensus::consensus_inner::ConsensusGraphInner;
18use crate::{
19    block_data_manager::BlockDataManager,
20    consensus::{
21        consensus_inner::consensus_executor::ConsensusExecutionConfiguration,
22        pos_handler::PosVerifier,
23    },
24    pow::{PowComputer, ProofOfWorkConfig},
25    statistics::SharedStatistics,
26    transaction_pool::SharedTransactionPool,
27    verification::VerificationConfig,
28    NodeType, Notifications,
29};
30
31use cfx_executor::spec::CommonParams;
32
33use super::config::ConsensusConfig;
34
35use cfx_types::H256;
36
37use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
38
39use parking_lot::{Mutex, RwLock};
40use primitives::EpochId;
41
42use std::sync::{atomic::AtomicBool, Arc};
43
44/// ConsensusGraph is a layer on top of SynchronizationGraph. A SyncGraph
45/// collect all blocks that the client has received so far, but a block can only
46/// be delivered to the ConsensusGraph if 1) the whole block content is
47/// available and 2) all of its past blocks are also in the ConsensusGraph.
48///
49/// ConsensusGraph maintains the TreeGraph structure of the client and
50/// implements *Timer Chain GHAST*/*Conflux* algorithm to determine the block
51/// total order. It dispatches transactions in epochs to ConsensusExecutor to
52/// process. To avoid executing too many execution reroll caused by transaction
53/// order oscillation. It defers the transaction execution for a few epochs.
54///
55/// When recovery from database, ConsensusGraph requires that 1) the data
56/// manager is in a consistent state, 2) the data manager stores the correct era
57/// genesis and era stable hash, and 3) the data manager contains correct *block
58/// status* for all blocks before era stable block (more restrictively speaking,
59/// whose past sets do not contain the stable block).
60pub struct ConsensusGraph {
61    pub inner: Arc<RwLock<ConsensusGraphInner>>,
62    pub txpool: SharedTransactionPool,
63    pub data_man: Arc<BlockDataManager>,
64    executor: Arc<ConsensusExecutor>,
65    statistics: SharedStatistics,
66    pub new_block_handler: ConsensusNewBlockHandler,
67    pub confirmation_meter: ConfirmationMeter,
68    /// Make sure that it is only modified when holding inner lock to prevent
69    /// any inconsistency
70    best_info: RwLock<Arc<BestInformation>>,
71    /// Set to `true` when we enter NormalPhase
72    pub ready_for_mining: AtomicBool,
73
74    /// The epoch id of the remotely synchronized state.
75    /// This is always `None` for archive nodes.
76    pub synced_epoch_id: Mutex<Option<EpochId>>,
77    pub config: ConsensusConfig,
78    pub params: CommonParams,
79}
80
81impl MallocSizeOf for ConsensusGraph {
82    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
83        let best_info_size = self.best_info.read().size_of(ops);
84        self.inner.read().size_of(ops)
85            + self.txpool.size_of(ops)
86            + self.data_man.size_of(ops)
87            + best_info_size
88    }
89}
90
91impl ConsensusGraph {
92    /// Build the ConsensusGraph with a specific era genesis block and various
93    /// other components. The execution will be skipped if bench_mode sets
94    /// to true.
95    pub fn with_era_genesis(
96        conf: ConsensusConfig, txpool: SharedTransactionPool,
97        statistics: SharedStatistics, data_man: Arc<BlockDataManager>,
98        pow_config: ProofOfWorkConfig, pow: Arc<PowComputer>,
99        era_genesis_block_hash: &H256, era_stable_block_hash: &H256,
100        notifications: Arc<Notifications>,
101        execution_conf: ConsensusExecutionConfiguration,
102        verification_config: VerificationConfig, node_type: NodeType,
103        pos_verifier: Arc<PosVerifier>, pivot_hint: Option<Arc<PivotHint>>,
104        params: CommonParams,
105    ) -> Self {
106        let inner =
107            Arc::new(RwLock::new(ConsensusGraphInner::with_era_genesis(
108                pow_config,
109                pow.clone(),
110                pos_verifier.clone(),
111                data_man.clone(),
112                conf.inner_conf.clone(),
113                era_genesis_block_hash,
114                era_stable_block_hash,
115            )));
116        let executor = ConsensusExecutor::start(
117            txpool.clone(),
118            data_man.clone(),
119            inner.clone(),
120            execution_conf,
121            verification_config,
122            conf.bench_mode,
123            pos_verifier.clone(),
124        );
125        let confirmation_meter = ConfirmationMeter::new();
126
127        let graph = ConsensusGraph {
128            inner,
129            txpool: txpool.clone(),
130            data_man: data_man.clone(),
131            executor: executor.clone(),
132            statistics: statistics.clone(),
133            new_block_handler: ConsensusNewBlockHandler::new(
134                conf.clone(),
135                txpool,
136                data_man,
137                executor,
138                statistics,
139                notifications,
140                node_type,
141                pos_verifier,
142                pivot_hint,
143            ),
144            confirmation_meter,
145            best_info: RwLock::new(Arc::new(Default::default())),
146            ready_for_mining: AtomicBool::new(false),
147            synced_epoch_id: Default::default(),
148            config: conf,
149            params,
150        };
151        graph.update_best_info(false /* ready_for_mining */);
152        graph
153            .txpool
154            .notify_new_best_info(graph.best_info.read_recursive().clone())
155            // FIXME: propogate error.
156            .expect(&concat!(file!(), ":", line!(), ":", column!()));
157        graph
158    }
159
160    /// Build the ConsensusGraph with the initial (checkpointed) genesis block
161    /// in the data manager and various other components. The execution will
162    /// be skipped if bench_mode sets to true.
163    pub fn new(
164        conf: ConsensusConfig, txpool: SharedTransactionPool,
165        statistics: SharedStatistics, data_man: Arc<BlockDataManager>,
166        pow_config: ProofOfWorkConfig, pow: Arc<PowComputer>,
167        notifications: Arc<Notifications>,
168        execution_conf: ConsensusExecutionConfiguration,
169        verification_conf: VerificationConfig, node_type: NodeType,
170        pos_verifier: Arc<PosVerifier>, pivot_hint: Option<Arc<PivotHint>>,
171        params: CommonParams,
172    ) -> Self {
173        let genesis_hash = data_man.get_cur_consensus_era_genesis_hash();
174        let stable_hash = data_man.get_cur_consensus_era_stable_hash();
175        ConsensusGraph::with_era_genesis(
176            conf,
177            txpool,
178            statistics,
179            data_man,
180            pow_config,
181            pow,
182            &genesis_hash,
183            &stable_hash,
184            notifications,
185            execution_conf,
186            verification_conf,
187            node_type,
188            pos_verifier,
189            pivot_hint,
190            params,
191        )
192    }
193
194    /// Get the number of processed blocks (i.e., the number of calls to
195    /// on_new_block()
196    #[cfg(feature = "consensus_bench")]
197    pub fn get_processed_block_count(&self) -> usize {
198        self.statistics.get_consensus_graph_processed_block_count()
199    }
200
201    pub fn config(&self) -> &ConsensusConfig { &self.config }
202
203    pub fn data_manager(&self) -> &Arc<BlockDataManager> { &self.data_man }
204
205    pub fn tx_pool(&self) -> &SharedTransactionPool { &self.txpool }
206}
207
208impl Drop for ConsensusGraph {
209    fn drop(&mut self) { self.executor.stop(); }
210}