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