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