ckb_chain/
lib.rs

1#![allow(missing_docs)]
2
3//! CKB chain service.
4//!
5//! [`ChainService`] background base on database, handle block importing,
6//! the [`ChainController`] is responsible for receive the request and returning response
7//!
8//! [`ChainService`]: chain/struct.ChainService.html
9//! [`ChainController`]: chain/struct.ChainController.html
10use ckb_channel::Request;
11use ckb_error::Error;
12use ckb_types::core::{BlockNumber, BlockView, EpochNumber, HeaderView};
13use ckb_types::packed::Byte32;
14use ckb_verification_traits::Switch;
15use std::sync::Arc;
16
17mod chain_controller;
18mod chain_service;
19mod init;
20mod init_load_unverified;
21mod orphan_broker;
22mod preload_unverified_blocks_channel;
23#[cfg(test)]
24mod tests;
25mod utils;
26pub mod verify;
27
28pub use chain_controller::ChainController;
29use ckb_logger::{error, info};
30use ckb_store::{ChainDB, ChainStore};
31use ckb_types::{BlockNumberAndHash, H256};
32pub use init::{ChainServiceScope, build_chain_services, start_chain_services};
33
34type ProcessBlockRequest = Request<LonelyBlock, ()>;
35type TruncateRequest = Request<Byte32, Result<(), Error>>;
36
37/// VerifyResult is the result type to represent the result of block verification
38///
39/// Ok(true) : it's a newly verified block
40/// Ok(false): it's a block is a uncle block, not verified
41/// Err(err) : it's a block which failed to verify
42pub type VerifyResult = Result<bool, Error>;
43
44/// VerifyCallback is the callback type to be called after block verification
45pub type VerifyCallback = Box<dyn FnOnce(VerifyResult) + Send + Sync>;
46
47/// RemoteBlock is received from ckb-sync and ckb-relayer
48pub struct RemoteBlock {
49    /// block
50    pub block: Arc<BlockView>,
51
52    /// Relayer and Synchronizer will have callback to ban peer
53    pub verify_callback: VerifyCallback,
54}
55
56/// LonelyBlock is the block which we have not check weather its parent is stored yet
57pub struct LonelyBlock {
58    /// block
59    pub block: Arc<BlockView>,
60
61    /// The Switch to control the verification process
62    pub switch: Option<Switch>,
63
64    /// The optional verify_callback
65    pub verify_callback: Option<VerifyCallback>,
66}
67
68/// LonelyBlock is the block which we have not check weather its parent is stored yet
69pub struct LonelyBlockHash {
70    /// block
71    pub block_number_and_hash: BlockNumberAndHash,
72
73    pub parent_hash: Byte32,
74
75    pub epoch_number: EpochNumber,
76
77    /// The Switch to control the verification process
78    pub switch: Option<Switch>,
79
80    /// The optional verify_callback
81    pub verify_callback: Option<VerifyCallback>,
82}
83
84impl From<LonelyBlock> for LonelyBlockHash {
85    fn from(val: LonelyBlock) -> Self {
86        let LonelyBlock {
87            block,
88            switch,
89            verify_callback,
90        } = val;
91        let block_hash_h256: H256 = block.hash().into();
92        let block_number: BlockNumber = block.number();
93        let parent_hash_h256: H256 = block.parent_hash().into();
94        let block_hash = block_hash_h256.into();
95        let parent_hash = parent_hash_h256.into();
96
97        let epoch_number: EpochNumber = block.epoch().number();
98
99        LonelyBlockHash {
100            block_number_and_hash: BlockNumberAndHash {
101                number: block_number,
102                hash: block_hash,
103            },
104            parent_hash,
105            epoch_number,
106            switch,
107            verify_callback,
108        }
109    }
110}
111
112impl LonelyBlockHash {
113    pub fn execute_callback(self, verify_result: VerifyResult) {
114        if let Some(verify_callback) = self.verify_callback {
115            verify_callback(verify_result);
116        }
117    }
118
119    pub fn number_hash(&self) -> BlockNumberAndHash {
120        self.block_number_and_hash.clone()
121    }
122
123    pub fn epoch_number(&self) -> EpochNumber {
124        self.epoch_number
125    }
126
127    pub fn hash(&self) -> Byte32 {
128        self.block_number_and_hash.hash()
129    }
130
131    pub fn parent_hash(&self) -> Byte32 {
132        self.parent_hash.clone()
133    }
134
135    pub fn number(&self) -> BlockNumber {
136        self.block_number_and_hash.number()
137    }
138}
139
140impl LonelyBlock {
141    pub(crate) fn block(&self) -> &Arc<BlockView> {
142        &self.block
143    }
144
145    pub fn switch(&self) -> Option<Switch> {
146        self.switch
147    }
148
149    pub fn execute_callback(self, verify_result: VerifyResult) {
150        if let Some(verify_callback) = self.verify_callback {
151            verify_callback(verify_result);
152        }
153    }
154}
155
156pub(crate) struct GlobalIndex {
157    pub(crate) number: BlockNumber,
158    pub(crate) hash: Byte32,
159    pub(crate) unseen: bool,
160}
161
162impl GlobalIndex {
163    pub(crate) fn new(number: BlockNumber, hash: Byte32, unseen: bool) -> GlobalIndex {
164        GlobalIndex {
165            number,
166            hash,
167            unseen,
168        }
169    }
170
171    pub(crate) fn forward(&mut self, hash: Byte32) {
172        self.number -= 1;
173        self.hash = hash;
174    }
175}
176
177/// UnverifiedBlock will be consumed by ConsumeUnverified thread
178struct UnverifiedBlock {
179    // block
180    block: Arc<BlockView>,
181    // the switch to control the verification process
182    switch: Option<Switch>,
183    // verify callback
184    verify_callback: Option<VerifyCallback>,
185    // parent header
186    parent_header: HeaderView,
187}
188
189pub(crate) fn delete_unverified_block(
190    store: &ChainDB,
191    block_hash: Byte32,
192    block_number: BlockNumber,
193    parent_hash: Byte32,
194) {
195    info!(
196        "parent: {}, deleting this block {}-{}",
197        parent_hash, block_number, block_hash,
198    );
199
200    let db_txn = store.begin_transaction();
201    let block_op: Option<BlockView> = db_txn.get_block(&block_hash);
202    match block_op {
203        Some(block) => {
204            if let Err(err) = db_txn.delete_block(&block) {
205                error!(
206                    "delete block {}-{} failed {:?}",
207                    block_number, block_hash, err
208                );
209                return;
210            }
211            if let Err(err) = db_txn.commit() {
212                error!(
213                    "commit delete block {}-{} failed {:?}",
214                    block_number, block_hash, err
215                );
216                return;
217            }
218
219            info!(
220                "parent: {}, deleted this block {}-{}",
221                parent_hash, block_number, block_hash,
222            );
223        }
224        None => {
225            error!(
226                "want to delete block {}-{}, but it not found in db",
227                block_number, block_hash
228            );
229        }
230    }
231}