1use crate::cache::StoreCache;
2use crate::data_loader_wrapper::BorrowedDataLoaderWrapper;
3use ckb_db::{
4 DBPinnableSlice,
5 iter::{DBIter, Direction, IteratorMode},
6};
7use ckb_db_schema::{
8 COLUMN_BLOCK_BODY, COLUMN_BLOCK_EPOCH, COLUMN_BLOCK_EXT, COLUMN_BLOCK_EXTENSION,
9 COLUMN_BLOCK_FILTER, COLUMN_BLOCK_FILTER_HASH, COLUMN_BLOCK_HEADER, COLUMN_BLOCK_PROPOSAL_IDS,
10 COLUMN_BLOCK_UNCLE, COLUMN_CELL, COLUMN_CELL_DATA, COLUMN_CELL_DATA_HASH,
11 COLUMN_CHAIN_ROOT_MMR, COLUMN_EPOCH, COLUMN_INDEX, COLUMN_META, COLUMN_TRANSACTION_INFO,
12 COLUMN_UNCLES, Col, META_CURRENT_EPOCH_KEY, META_LATEST_BUILT_FILTER_DATA_KEY,
13 META_TIP_HEADER_KEY,
14};
15use ckb_freezer::Freezer;
16use ckb_types::{
17 bytes::Bytes,
18 core::{
19 BlockExt, BlockNumber, BlockView, EpochExt, EpochNumber, HeaderView, TransactionInfo,
20 TransactionView, UncleBlockVecView, cell::CellMeta,
21 },
22 packed::{self, OutPoint},
23 prelude::*,
24};
25
26pub trait ChainStore: Send + Sync + Sized {
28 fn cache(&self) -> Option<&StoreCache>;
30 fn freezer(&self) -> Option<&Freezer>;
32 fn get(&self, col: Col, key: &[u8]) -> Option<DBPinnableSlice<'_>>;
34 fn get_iter(&self, col: Col, mode: IteratorMode) -> DBIter<'_>;
36 fn borrow_as_data_loader(&self) -> BorrowedDataLoaderWrapper<'_, Self> {
38 BorrowedDataLoaderWrapper::new(self)
39 }
40
41 fn get_block(&self, h: &packed::Byte32) -> Option<BlockView> {
43 let header = self.get_block_header(h)?;
44 if let Some(freezer) = self.freezer()
45 && header.number() > 0
46 && header.number() < freezer.number()
47 {
48 let raw_block = freezer.retrieve(header.number()).expect("block frozen")?;
49 let raw_block = packed::BlockReader::from_compatible_slice(&raw_block)
50 .expect("checked data")
51 .to_entity();
52 return Some(raw_block.into_view());
53 }
54 let body = self.get_block_body(h);
55 let uncles = self
56 .get_block_uncles(h)
57 .expect("block uncles must be stored");
58 let proposals = self
59 .get_block_proposal_txs_ids(h)
60 .expect("block proposal_ids must be stored");
61 let extension_opt = self.get_block_extension(h);
62
63 let block = if let Some(extension) = extension_opt {
64 BlockView::new_unchecked_with_extension(header, uncles, body, proposals, extension)
65 } else {
66 BlockView::new_unchecked(header, uncles, body, proposals)
67 };
68 Some(block)
69 }
70
71 fn get_block_header(&self, hash: &packed::Byte32) -> Option<HeaderView> {
73 if let Some(cache) = self.cache()
74 && let Some(header) = cache.headers.lock().get(hash)
75 {
76 return Some(header.clone());
77 };
78 let ret = self.get(COLUMN_BLOCK_HEADER, hash.as_slice()).map(|slice| {
79 let reader = packed::HeaderViewReader::from_slice_should_be_ok(slice.as_ref());
80 Into::<HeaderView>::into(reader)
81 });
82
83 if let Some(cache) = self.cache() {
84 ret.inspect(|header| {
85 cache.headers.lock().put(hash.clone(), header.clone());
86 })
87 } else {
88 ret
89 }
90 }
91
92 fn get_block_body(&self, hash: &packed::Byte32) -> Vec<TransactionView> {
94 let prefix = hash.as_slice();
95 self.get_iter(
96 COLUMN_BLOCK_BODY,
97 IteratorMode::From(prefix, Direction::Forward),
98 )
99 .take_while(|(key, _)| key.starts_with(prefix))
100 .map(|(_key, value)| {
101 let reader = packed::TransactionViewReader::from_slice_should_be_ok(value.as_ref());
102 Into::<TransactionView>::into(reader)
103 })
104 .collect()
105 }
106
107 fn get_unfrozen_block(&self, hash: &packed::Byte32) -> Option<BlockView> {
109 let header = self
110 .get(COLUMN_BLOCK_HEADER, hash.as_slice())
111 .map(|slice| {
112 let reader = packed::HeaderViewReader::from_slice_should_be_ok(slice.as_ref());
113 Into::<HeaderView>::into(reader)
114 })?;
115
116 let body = self.get_block_body(hash);
117
118 let uncles = self
119 .get(COLUMN_BLOCK_UNCLE, hash.as_slice())
120 .map(|slice| {
121 let reader =
122 packed::UncleBlockVecViewReader::from_slice_should_be_ok(slice.as_ref());
123 Into::<UncleBlockVecView>::into(reader)
124 })
125 .expect("block uncles must be stored");
126
127 let proposals = self
128 .get(COLUMN_BLOCK_PROPOSAL_IDS, hash.as_slice())
129 .map(|slice| {
130 packed::ProposalShortIdVecReader::from_slice_should_be_ok(slice.as_ref())
131 .to_entity()
132 })
133 .expect("block proposal_ids must be stored");
134
135 let extension_opt = self
136 .get(COLUMN_BLOCK_EXTENSION, hash.as_slice())
137 .map(|slice| packed::BytesReader::from_slice_should_be_ok(slice.as_ref()).to_entity());
138
139 let block = if let Some(extension) = extension_opt {
140 BlockView::new_unchecked_with_extension(header, uncles, body, proposals, extension)
141 } else {
142 BlockView::new_unchecked(header, uncles, body, proposals)
143 };
144
145 Some(block)
146 }
147
148 fn get_block_txs_hashes(&self, hash: &packed::Byte32) -> Vec<packed::Byte32> {
150 if let Some(cache) = self.cache()
151 && let Some(hashes) = cache.block_tx_hashes.lock().get(hash)
152 {
153 return hashes.clone();
154 };
155
156 let prefix = hash.as_slice();
157 let ret: Vec<_> = self
158 .get_iter(
159 COLUMN_BLOCK_BODY,
160 IteratorMode::From(prefix, Direction::Forward),
161 )
162 .take_while(|(key, _)| key.starts_with(prefix))
163 .map(|(_key, value)| {
164 let reader = packed::TransactionViewReader::from_slice_should_be_ok(value.as_ref());
165 reader.hash().to_entity()
166 })
167 .collect();
168
169 if let Some(cache) = self.cache() {
170 cache.block_tx_hashes.lock().put(hash.clone(), ret.clone());
171 }
172
173 ret
174 }
175
176 fn get_block_proposal_txs_ids(
178 &self,
179 hash: &packed::Byte32,
180 ) -> Option<packed::ProposalShortIdVec> {
181 if let Some(cache) = self.cache()
182 && let Some(data) = cache.block_proposals.lock().get(hash)
183 {
184 return Some(data.clone());
185 };
186
187 let ret = self
188 .get(COLUMN_BLOCK_PROPOSAL_IDS, hash.as_slice())
189 .map(|slice| {
190 packed::ProposalShortIdVecReader::from_slice_should_be_ok(slice.as_ref())
191 .to_entity()
192 });
193
194 if let Some(cache) = self.cache() {
195 ret.inspect(|data| {
196 cache.block_proposals.lock().put(hash.clone(), data.clone());
197 })
198 } else {
199 ret
200 }
201 }
202
203 fn get_block_uncles(&self, hash: &packed::Byte32) -> Option<UncleBlockVecView> {
205 if let Some(cache) = self.cache()
206 && let Some(data) = cache.block_uncles.lock().get(hash)
207 {
208 return Some(data.clone());
209 };
210
211 let ret = self.get(COLUMN_BLOCK_UNCLE, hash.as_slice()).map(|slice| {
212 let reader = packed::UncleBlockVecViewReader::from_slice_should_be_ok(slice.as_ref());
213 Into::<UncleBlockVecView>::into(reader)
214 });
215
216 if let Some(cache) = self.cache() {
217 ret.inspect(|uncles| {
218 cache.block_uncles.lock().put(hash.clone(), uncles.clone());
219 })
220 } else {
221 ret
222 }
223 }
224
225 fn get_block_extension(&self, hash: &packed::Byte32) -> Option<packed::Bytes> {
227 if let Some(cache) = self.cache()
228 && let Some(data) = cache.block_extensions.lock().get(hash)
229 {
230 return data.clone();
231 };
232
233 let ret = self
234 .get(COLUMN_BLOCK_EXTENSION, hash.as_slice())
235 .map(|slice| packed::BytesReader::from_slice_should_be_ok(slice.as_ref()).to_entity());
236
237 if let Some(cache) = self.cache() {
238 cache.block_extensions.lock().put(hash.clone(), ret.clone());
239 }
240 ret
241 }
242
243 fn get_block_ext(&self, block_hash: &packed::Byte32) -> Option<BlockExt> {
247 self.get(COLUMN_BLOCK_EXT, block_hash.as_slice())
248 .map(|slice| {
249 let reader =
250 packed::BlockExtReader::from_compatible_slice_should_be_ok(slice.as_ref());
251 match reader.count_extra_fields() {
252 0 => reader.into(),
253 2 => packed::BlockExtV1Reader::from_slice_should_be_ok(slice.as_ref()).into(),
254 _ => {
255 panic!(
256 "BlockExt storage field count doesn't match, expect 7 or 5, actual {}",
257 reader.field_count()
258 )
259 }
260 }
261 })
262 }
263
264 fn get_block_hash(&self, number: BlockNumber) -> Option<packed::Byte32> {
266 let block_number: packed::Uint64 = number.into();
267 self.get(COLUMN_INDEX, block_number.as_slice())
268 .map(|raw| packed::Byte32Reader::from_slice_should_be_ok(raw.as_ref()).to_entity())
269 }
270
271 fn get_block_number(&self, hash: &packed::Byte32) -> Option<BlockNumber> {
273 self.get(COLUMN_INDEX, hash.as_slice())
274 .map(|raw| packed::Uint64Reader::from_slice_should_be_ok(raw.as_ref()).into())
275 }
276
277 fn is_main_chain(&self, hash: &packed::Byte32) -> bool {
279 self.get(COLUMN_INDEX, hash.as_slice()).is_some()
280 }
281
282 fn get_tip_header(&self) -> Option<HeaderView> {
284 self.get(COLUMN_META, META_TIP_HEADER_KEY).and_then(|raw| {
285 self.get_block_header(
286 &packed::Byte32Reader::from_slice_should_be_ok(raw.as_ref()).to_entity(),
287 )
288 })
289 }
290
291 fn transaction_exists(&self, hash: &packed::Byte32) -> bool {
296 self.get(COLUMN_TRANSACTION_INFO, hash.as_slice()).is_some()
297 }
298
299 fn get_transaction(&self, hash: &packed::Byte32) -> Option<(TransactionView, packed::Byte32)> {
301 self.get_transaction_with_info(hash)
302 .map(|(tx, tx_info)| (tx, tx_info.block_hash))
303 }
304
305 fn get_transaction_info(&self, hash: &packed::Byte32) -> Option<TransactionInfo> {
307 self.get(COLUMN_TRANSACTION_INFO, hash.as_slice())
308 .map(|slice| {
309 let reader = packed::TransactionInfoReader::from_slice_should_be_ok(slice.as_ref());
310 Into::<TransactionInfo>::into(reader)
311 })
312 }
313
314 fn get_transaction_with_info(
316 &self,
317 hash: &packed::Byte32,
318 ) -> Option<(TransactionView, TransactionInfo)> {
319 let tx_info = self.get_transaction_info(hash)?;
320 if let Some(freezer) = self.freezer()
321 && tx_info.block_number > 0
322 && tx_info.block_number < freezer.number()
323 {
324 let raw_block = freezer
325 .retrieve(tx_info.block_number)
326 .expect("block frozen")?;
327 let raw_block_reader =
328 packed::BlockReader::from_compatible_slice(&raw_block).expect("checked data");
329 let tx_reader = raw_block_reader.transactions().get(tx_info.index)?;
330 return Some((tx_reader.to_entity().into_view(), tx_info));
331 }
332 self.get(COLUMN_BLOCK_BODY, tx_info.key().as_slice())
333 .map(|slice| {
334 let reader = packed::TransactionViewReader::from_slice_should_be_ok(slice.as_ref());
335 (reader.into(), tx_info)
336 })
337 }
338
339 fn have_cell(&self, out_point: &OutPoint) -> bool {
341 let key = out_point.to_cell_key();
342 self.get(COLUMN_CELL, &key).is_some()
343 }
344
345 fn get_cell(&self, out_point: &OutPoint) -> Option<CellMeta> {
347 let key = out_point.to_cell_key();
348 self.get(COLUMN_CELL, &key).map(|slice| {
349 let reader = packed::CellEntryReader::from_slice_should_be_ok(slice.as_ref());
350 build_cell_meta_from_reader(out_point.clone(), reader)
351 })
352 }
353
354 fn get_cell_data(&self, out_point: &OutPoint) -> Option<(Bytes, packed::Byte32)> {
356 let key = out_point.to_cell_key();
357 if let Some(cache) = self.cache()
358 && let Some(cached) = cache.cell_data.lock().get(&key)
359 {
360 return Some(cached.clone());
361 };
362
363 let ret = self.get(COLUMN_CELL_DATA, &key).map(|slice| {
364 if !slice.as_ref().is_empty() {
365 let reader = packed::CellDataEntryReader::from_slice_should_be_ok(slice.as_ref());
366 let data = reader.output_data().into();
367 let data_hash = reader.output_data_hash().to_entity();
368 (data, data_hash)
369 } else {
370 (Bytes::new(), packed::Byte32::zero())
371 }
372 });
373
374 if let Some(cache) = self.cache() {
375 ret.inspect(|cached| {
376 cache.cell_data.lock().put(key, cached.clone());
377 })
378 } else {
379 ret
380 }
381 }
382
383 fn get_cell_data_hash(&self, out_point: &OutPoint) -> Option<packed::Byte32> {
385 let key = out_point.to_cell_key();
386 if let Some(cache) = self.cache()
387 && let Some(cached) = cache.cell_data_hash.lock().get(&key)
388 {
389 return Some(cached.clone());
390 };
391
392 let ret = self.get(COLUMN_CELL_DATA_HASH, &key).map(|raw| {
393 if !raw.as_ref().is_empty() {
394 packed::Byte32Reader::from_slice_should_be_ok(raw.as_ref()).to_entity()
395 } else {
396 packed::Byte32::zero()
397 }
398 });
399
400 if let Some(cache) = self.cache() {
401 ret.inspect(|cached| {
402 cache.cell_data_hash.lock().put(key, cached.clone());
403 })
404 } else {
405 ret
406 }
407 }
408
409 fn get_current_epoch_ext(&self) -> Option<EpochExt> {
411 self.get(COLUMN_META, META_CURRENT_EPOCH_KEY)
412 .map(|slice| packed::EpochExtReader::from_slice_should_be_ok(slice.as_ref()).into())
413 }
414
415 fn get_epoch_ext(&self, hash: &packed::Byte32) -> Option<EpochExt> {
417 self.get(COLUMN_EPOCH, hash.as_slice())
418 .map(|slice| packed::EpochExtReader::from_slice_should_be_ok(slice.as_ref()).into())
419 }
420
421 fn get_epoch_index(&self, number: EpochNumber) -> Option<packed::Byte32> {
423 let epoch_number: packed::Uint64 = number.into();
424 self.get(COLUMN_EPOCH, epoch_number.as_slice())
425 .map(|raw| packed::Byte32Reader::from_slice_should_be_ok(raw.as_ref()).to_entity())
426 }
427
428 fn get_block_epoch_index(&self, block_hash: &packed::Byte32) -> Option<packed::Byte32> {
430 self.get(COLUMN_BLOCK_EPOCH, block_hash.as_slice())
431 .map(|raw| packed::Byte32Reader::from_slice_should_be_ok(raw.as_ref()).to_entity())
432 }
433
434 fn get_block_epoch(&self, hash: &packed::Byte32) -> Option<EpochExt> {
436 self.get_block_epoch_index(hash)
437 .and_then(|index| self.get_epoch_ext(&index))
438 }
439
440 fn is_uncle(&self, hash: &packed::Byte32) -> bool {
442 self.get(COLUMN_UNCLES, hash.as_slice()).is_some()
443 }
444
445 fn get_uncle_header(&self, hash: &packed::Byte32) -> Option<HeaderView> {
447 self.get(COLUMN_UNCLES, hash.as_slice()).map(|slice| {
448 let reader = packed::HeaderViewReader::from_slice_should_be_ok(slice.as_ref());
449 Into::<HeaderView>::into(reader)
450 })
451 }
452
453 fn block_exists(&self, hash: &packed::Byte32) -> bool {
455 if let Some(cache) = self.cache()
456 && cache.headers.lock().get(hash).is_some()
457 {
458 return true;
459 };
460 self.get(COLUMN_BLOCK_HEADER, hash.as_slice()).is_some()
461 }
462
463 fn get_cellbase(&self, hash: &packed::Byte32) -> Option<TransactionView> {
465 let key = packed::TransactionKey::new_builder()
466 .block_hash(hash.to_owned())
467 .build();
468 self.get(COLUMN_BLOCK_BODY, key.as_slice()).map(|slice| {
469 let reader = packed::TransactionViewReader::from_slice_should_be_ok(slice.as_ref());
470 Into::<TransactionView>::into(reader)
471 })
472 }
473
474 fn get_latest_built_filter_data_block_hash(&self) -> Option<packed::Byte32> {
476 self.get(COLUMN_META, META_LATEST_BUILT_FILTER_DATA_KEY)
477 .map(|raw| packed::Byte32Reader::from_slice_should_be_ok(raw.as_ref()).to_entity())
478 }
479
480 fn get_block_filter(&self, hash: &packed::Byte32) -> Option<packed::Bytes> {
482 self.get(COLUMN_BLOCK_FILTER, hash.as_slice())
483 .map(|slice| packed::BytesReader::from_slice_should_be_ok(slice.as_ref()).to_entity())
484 }
485
486 fn get_block_filter_hash(&self, hash: &packed::Byte32) -> Option<packed::Byte32> {
488 self.get(COLUMN_BLOCK_FILTER_HASH, hash.as_slice())
489 .map(|slice| packed::Byte32Reader::from_slice_should_be_ok(slice.as_ref()).to_entity())
490 }
491
492 fn get_packed_block(&self, hash: &packed::Byte32) -> Option<packed::Block> {
494 let header = self
495 .get(COLUMN_BLOCK_HEADER, hash.as_slice())
496 .map(|slice| {
497 let reader = packed::HeaderViewReader::from_slice_should_be_ok(slice.as_ref());
498 reader.data().to_entity()
499 })?;
500
501 let prefix = hash.as_slice();
502 let transactions: packed::TransactionVec = self
503 .get_iter(
504 COLUMN_BLOCK_BODY,
505 IteratorMode::From(prefix, Direction::Forward),
506 )
507 .take_while(|(key, _)| key.starts_with(prefix))
508 .map(|(_key, value)| {
509 let reader = packed::TransactionViewReader::from_slice_should_be_ok(value.as_ref());
510 reader.data().to_entity()
511 })
512 .collect::<Vec<_>>()
513 .into();
514
515 let uncles = self.get_block_uncles(hash)?;
516 let proposals = self.get_block_proposal_txs_ids(hash)?;
517 let extension_opt = self.get_block_extension(hash);
518
519 let block = if let Some(extension) = extension_opt {
520 packed::BlockV1::new_builder()
521 .header(header)
522 .uncles(uncles.data())
523 .transactions(transactions)
524 .proposals(proposals)
525 .extension(extension)
526 .build()
527 .as_v0()
528 } else {
529 packed::Block::new_builder()
530 .header(header)
531 .uncles(uncles.data())
532 .transactions(transactions)
533 .proposals(proposals)
534 .build()
535 };
536
537 Some(block)
538 }
539
540 fn get_packed_block_header(&self, hash: &packed::Byte32) -> Option<packed::Header> {
542 self.get(COLUMN_BLOCK_HEADER, hash.as_slice()).map(|slice| {
543 let reader = packed::HeaderViewReader::from_slice_should_be_ok(slice.as_ref());
544 reader.data().to_entity()
545 })
546 }
547
548 fn get_header_digest(&self, position_u64: u64) -> Option<packed::HeaderDigest> {
550 let position: packed::Uint64 = position_u64.into();
551 self.get(COLUMN_CHAIN_ROOT_MMR, position.as_slice())
552 .map(|slice| {
553 let reader = packed::HeaderDigestReader::from_slice_should_be_ok(slice.as_ref());
554 reader.to_entity()
555 })
556 }
557
558 fn get_ancestor(&self, base: &packed::Byte32, number: BlockNumber) -> Option<HeaderView> {
560 let header = self.get_block_header(base)?;
561 if number > header.number() {
562 None
563 } else if number == header.number() {
564 Some(header)
565 } else if self.is_main_chain(base) {
566 self.get_block_hash(number)
567 .and_then(|hash| self.get_block_header(&hash))
568 } else {
569 self.get_ancestor(&header.parent_hash(), number)
570 }
571 }
572}
573
574fn build_cell_meta_from_reader(out_point: OutPoint, reader: packed::CellEntryReader) -> CellMeta {
575 CellMeta {
576 out_point,
577 cell_output: reader.output().to_entity(),
578 transaction_info: Some(TransactionInfo {
579 block_number: reader.block_number().into(),
580 block_hash: reader.block_hash().to_entity(),
581 block_epoch: reader.block_epoch().into(),
582 index: reader.index().into(),
583 }),
584 data_bytes: reader.data_size().into(),
585 mem_cell_data: None,
586 mem_cell_data_hash: None,
587 }
588}