1#![allow(missing_docs)]
2
3use 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
37pub type VerifyResult = Result<bool, Error>;
43
44pub type VerifyCallback = Box<dyn FnOnce(VerifyResult) + Send + Sync>;
46
47pub struct RemoteBlock {
49 pub block: Arc<BlockView>,
51
52 pub verify_callback: VerifyCallback,
54}
55
56pub struct LonelyBlock {
58 pub block: Arc<BlockView>,
60
61 pub switch: Option<Switch>,
63
64 pub verify_callback: Option<VerifyCallback>,
66}
67
68pub struct LonelyBlockHash {
70 pub block_number_and_hash: BlockNumberAndHash,
72
73 pub parent_hash: Byte32,
74
75 pub epoch_number: EpochNumber,
76
77 pub switch: Option<Switch>,
79
80 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
177struct UnverifiedBlock {
179 block: Arc<BlockView>,
181 switch: Option<Switch>,
183 verify_callback: Option<VerifyCallback>,
185 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}