ckb_chain/
chain_controller.rs

1//! CKB chain controller.
2#![allow(missing_docs)]
3#![allow(elided_named_lifetimes)]
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        if Request::call(&self.process_block_sender, lonely_block).is_none() {
63            error!("Chain service has gone")
64        }
65    }
66
67    /// MinerRpc::submit_block and `ckb import` need this blocking way to process block
68    pub fn blocking_process_block(&self, block: Arc<BlockView>) -> VerifyResult {
69        self.blocking_process_block_internal(block, None)
70    }
71
72    /// `IntegrationTestRpcImpl::process_block_without_verify` need this
73    pub fn blocking_process_block_with_switch(
74        &self,
75        block: Arc<BlockView>,
76        switch: Switch,
77    ) -> VerifyResult {
78        self.blocking_process_block_internal(block, Some(switch))
79    }
80
81    fn blocking_process_block_internal(
82        &self,
83        block: Arc<BlockView>,
84        switch: Option<Switch>,
85    ) -> VerifyResult {
86        let (verify_result_tx, verify_result_rx) = ckb_channel::oneshot::channel::<VerifyResult>();
87
88        let verify_callback = {
89            move |result: VerifyResult| {
90                if let Err(err) = verify_result_tx.send(result) {
91                    error!(
92                        "blocking send verify_result failed: {}, this shouldn't happen",
93                        err
94                    )
95                }
96            }
97        };
98
99        let lonely_block = LonelyBlock {
100            block,
101            switch,
102            verify_callback: Some(Box::new(verify_callback)),
103        };
104
105        self.asynchronous_process_lonely_block(lonely_block);
106        verify_result_rx.recv().unwrap_or_else(|err| {
107            Err(InternalErrorKind::System
108                .other(format!("blocking recv verify_result failed: {}", err))
109                .into())
110        })
111    }
112
113    /// Truncate chain to specified target
114    ///
115    /// Should use for testing only
116    pub fn truncate(&self, target_tip_hash: Byte32) -> Result<(), Error> {
117        Request::call(&self.truncate_sender, target_tip_hash).unwrap_or_else(|| {
118            Err(InternalErrorKind::System
119                .other("Chain service has gone")
120                .into())
121        })
122    }
123
124    /// `Relayer::reconstruct_block` need this
125    pub fn get_orphan_block(&self, store: &ChainDB, hash: &Byte32) -> Option<Arc<BlockView>> {
126        self.orphan_block_broker.get_block(store, hash)
127    }
128
129    /// `NetRpcImpl::sync_state` rpc need this
130    pub fn orphan_blocks_len(&self) -> usize {
131        self.orphan_block_broker.len()
132    }
133}