Skip to main content

ckb_chain/
chain_controller.rs

1//! CKB chain controller.
2#![allow(missing_docs)]
3#![allow(mismatched_lifetime_syntaxes)]
4
5use crate::utils::orphan_block_pool::OrphanBlockPool;
6use crate::{LonelyBlock, ProcessBlockRequest, RemoteBlock, TruncateRequest, VerifyResult};
7use ckb_channel::{Request, Sender};
8use ckb_error::{Error, InternalErrorKind};
9use ckb_logger::{self, error};
10use ckb_store::ChainDB;
11use ckb_types::{core::BlockView, packed::Byte32};
12use ckb_verification_traits::Switch;
13use std::sync::Arc;
14use std::sync::atomic::AtomicBool;
15
16/// Controller to the chain service.
17///
18/// The controller is internally reference-counted and can be freely cloned.
19///
20/// A controller can invoke ChainService methods.
21#[cfg_attr(feature = "mock", faux::create)]
22#[derive(Clone)]
23pub struct ChainController {
24    process_block_sender: Sender<ProcessBlockRequest>,
25    truncate_sender: Sender<TruncateRequest>,
26    orphan_block_broker: Arc<OrphanBlockPool>,
27
28    is_verifying_unverified_blocks_on_startup: Arc<AtomicBool>,
29}
30
31#[cfg_attr(feature = "mock", faux::methods)]
32impl ChainController {
33    pub(crate) fn new(
34        process_block_sender: Sender<ProcessBlockRequest>,
35        truncate_sender: Sender<TruncateRequest>,
36        orphan_block_broker: Arc<OrphanBlockPool>,
37        is_verifying_unverified_blocks_on_startup: Arc<AtomicBool>,
38    ) -> Self {
39        ChainController {
40            process_block_sender,
41            truncate_sender,
42            orphan_block_broker,
43            is_verifying_unverified_blocks_on_startup,
44        }
45    }
46
47    pub fn is_verifying_unverified_blocks_on_startup(&self) -> bool {
48        self.is_verifying_unverified_blocks_on_startup
49            .load(std::sync::atomic::Ordering::Acquire)
50    }
51
52    pub fn asynchronous_process_remote_block(&self, remote_block: RemoteBlock) {
53        let lonely_block = LonelyBlock {
54            block: remote_block.block,
55            verify_callback: Some(remote_block.verify_callback),
56            switch: None,
57        };
58        self.asynchronous_process_lonely_block(lonely_block);
59    }
60
61    pub fn asynchronous_process_lonely_block(&self, lonely_block: LonelyBlock) {
62        Request::call_without_response(&self.process_block_sender, lonely_block);
63    }
64
65    /// MinerRpc::submit_block and `ckb import` need this blocking way to process block
66    pub fn blocking_process_block(&self, block: Arc<BlockView>) -> VerifyResult {
67        self.blocking_process_block_internal(block, None)
68    }
69
70    /// `IntegrationTestRpcImpl::process_block_without_verify` need this
71    pub fn blocking_process_block_with_switch(
72        &self,
73        block: Arc<BlockView>,
74        switch: Switch,
75    ) -> VerifyResult {
76        self.blocking_process_block_internal(block, Some(switch))
77    }
78
79    fn blocking_process_block_internal(
80        &self,
81        block: Arc<BlockView>,
82        switch: Option<Switch>,
83    ) -> VerifyResult {
84        let (verify_result_tx, verify_result_rx) = ckb_channel::oneshot::channel::<VerifyResult>();
85
86        let verify_callback = {
87            move |result: VerifyResult| {
88                if let Err(err) = verify_result_tx.send(result) {
89                    error!(
90                        "blocking send verify_result failed: {}, this shouldn't happen",
91                        err
92                    )
93                }
94            }
95        };
96
97        let lonely_block = LonelyBlock {
98            block,
99            switch,
100            verify_callback: Some(Box::new(verify_callback)),
101        };
102
103        self.asynchronous_process_lonely_block(lonely_block);
104        verify_result_rx.recv().unwrap_or_else(|err| {
105            Err(InternalErrorKind::System
106                .other(format!("blocking recv verify_result failed: {}", err))
107                .into())
108        })
109    }
110
111    /// Truncate chain to specified target
112    ///
113    /// Should use for testing only
114    pub fn truncate(&self, target_tip_hash: Byte32) -> Result<(), Error> {
115        Request::call(&self.truncate_sender, target_tip_hash).unwrap_or_else(|| {
116            Err(InternalErrorKind::System
117                .other("Chain service has gone")
118                .into())
119        })
120    }
121
122    /// `Relayer::reconstruct_block` need this
123    pub fn get_orphan_block(&self, store: &ChainDB, hash: &Byte32) -> Option<Arc<BlockView>> {
124        self.orphan_block_broker.get_block(store, hash)
125    }
126
127    /// `NetRpcImpl::sync_state` rpc need this
128    pub fn orphan_blocks_len(&self) -> usize {
129        self.orphan_block_broker.len()
130    }
131}