ckb_store/
store.rs

1use crate::cache::StoreCache;
2use crate::data_loader_wrapper::BorrowedDataLoaderWrapper;
3use ckb_db::{
4    iter::{DBIter, Direction, IteratorMode},
5    DBPinnableSlice,
6};
7use ckb_db_schema::{
8    Col, 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, META_CURRENT_EPOCH_KEY, META_LATEST_BUILT_FILTER_DATA_KEY, META_TIP_HEADER_KEY,
13};
14use ckb_freezer::Freezer;
15use ckb_types::{
16    bytes::Bytes,
17    core::{
18        cell::CellMeta, BlockExt, BlockNumber, BlockView, EpochExt, EpochNumber, HeaderView,
19        TransactionInfo, TransactionView, UncleBlockVecView,
20    },
21    packed::{self, OutPoint},
22    prelude::*,
23};
24
25/// The `ChainStore` trait provides chain data store interface
26pub trait ChainStore: Send + Sync + Sized {
27    /// Return cache reference
28    fn cache(&self) -> Option<&StoreCache>;
29    /// Return freezer reference
30    fn freezer(&self) -> Option<&Freezer>;
31    /// Return the bytes associated with a key value and the given column family.
32    fn get(&self, col: Col, key: &[u8]) -> Option<DBPinnableSlice>;
33    /// Return an iterator over the database key-value pairs in the given column family.
34    fn get_iter(&self, col: Col, mode: IteratorMode) -> DBIter;
35    /// Return the borrowed data loader wrapper
36    fn borrow_as_data_loader(&self) -> BorrowedDataLoaderWrapper<Self> {
37        BorrowedDataLoaderWrapper::new(self)
38    }
39
40    /// Get block by block header hash
41    fn get_block(&self, h: &packed::Byte32) -> Option<BlockView> {
42        let header = self.get_block_header(h)?;
43        if let Some(freezer) = self.freezer() {
44            if header.number() > 0 && header.number() < freezer.number() {
45                let raw_block = freezer.retrieve(header.number()).expect("block frozen")?;
46                let raw_block = packed::BlockReader::from_compatible_slice(&raw_block)
47                    .expect("checked data")
48                    .to_entity();
49                return Some(raw_block.into_view());
50            }
51        }
52        let body = self.get_block_body(h);
53        let uncles = self
54            .get_block_uncles(h)
55            .expect("block uncles must be stored");
56        let proposals = self
57            .get_block_proposal_txs_ids(h)
58            .expect("block proposal_ids must be stored");
59        let extension_opt = self.get_block_extension(h);
60
61        let block = if let Some(extension) = extension_opt {
62            BlockView::new_unchecked_with_extension(header, uncles, body, proposals, extension)
63        } else {
64            BlockView::new_unchecked(header, uncles, body, proposals)
65        };
66        Some(block)
67    }
68
69    /// Get header by block header hash
70    fn get_block_header(&self, hash: &packed::Byte32) -> Option<HeaderView> {
71        if let Some(cache) = self.cache() {
72            if let Some(header) = cache.headers.lock().get(hash) {
73                return Some(header.clone());
74            }
75        };
76        let ret = self.get(COLUMN_BLOCK_HEADER, hash.as_slice()).map(|slice| {
77            let reader = packed::HeaderViewReader::from_slice_should_be_ok(slice.as_ref());
78            Unpack::<HeaderView>::unpack(&reader)
79        });
80
81        if let Some(cache) = self.cache() {
82            ret.inspect(|header| {
83                cache.headers.lock().put(hash.clone(), header.clone());
84            })
85        } else {
86            ret
87        }
88    }
89
90    /// Get block body by block header hash
91    fn get_block_body(&self, hash: &packed::Byte32) -> Vec<TransactionView> {
92        let prefix = hash.as_slice();
93        self.get_iter(
94            COLUMN_BLOCK_BODY,
95            IteratorMode::From(prefix, Direction::Forward),
96        )
97        .take_while(|(key, _)| key.starts_with(prefix))
98        .map(|(_key, value)| {
99            let reader = packed::TransactionViewReader::from_slice_should_be_ok(value.as_ref());
100            Unpack::<TransactionView>::unpack(&reader)
101        })
102        .collect()
103    }
104
105    /// Get unfrozen block from ky-store with given hash
106    fn get_unfrozen_block(&self, hash: &packed::Byte32) -> Option<BlockView> {
107        let header = self
108            .get(COLUMN_BLOCK_HEADER, hash.as_slice())
109            .map(|slice| {
110                let reader = packed::HeaderViewReader::from_slice_should_be_ok(slice.as_ref());
111                Unpack::<HeaderView>::unpack(&reader)
112            })?;
113
114        let body = self.get_block_body(hash);
115
116        let uncles = self
117            .get(COLUMN_BLOCK_UNCLE, hash.as_slice())
118            .map(|slice| {
119                let reader =
120                    packed::UncleBlockVecViewReader::from_slice_should_be_ok(slice.as_ref());
121                Unpack::<UncleBlockVecView>::unpack(&reader)
122            })
123            .expect("block uncles must be stored");
124
125        let proposals = self
126            .get(COLUMN_BLOCK_PROPOSAL_IDS, hash.as_slice())
127            .map(|slice| {
128                packed::ProposalShortIdVecReader::from_slice_should_be_ok(slice.as_ref())
129                    .to_entity()
130            })
131            .expect("block proposal_ids must be stored");
132
133        let extension_opt = self
134            .get(COLUMN_BLOCK_EXTENSION, hash.as_slice())
135            .map(|slice| packed::BytesReader::from_slice_should_be_ok(slice.as_ref()).to_entity());
136
137        let block = if let Some(extension) = extension_opt {
138            BlockView::new_unchecked_with_extension(header, uncles, body, proposals, extension)
139        } else {
140            BlockView::new_unchecked(header, uncles, body, proposals)
141        };
142
143        Some(block)
144    }
145
146    /// Get all transaction-hashes in block body by block header hash
147    fn get_block_txs_hashes(&self, hash: &packed::Byte32) -> Vec<packed::Byte32> {
148        if let Some(cache) = self.cache() {
149            if let Some(hashes) = cache.block_tx_hashes.lock().get(hash) {
150                return hashes.clone();
151            }
152        };
153
154        let prefix = hash.as_slice();
155        let ret: Vec<_> = self
156            .get_iter(
157                COLUMN_BLOCK_BODY,
158                IteratorMode::From(prefix, Direction::Forward),
159            )
160            .take_while(|(key, _)| key.starts_with(prefix))
161            .map(|(_key, value)| {
162                let reader = packed::TransactionViewReader::from_slice_should_be_ok(value.as_ref());
163                reader.hash().to_entity()
164            })
165            .collect();
166
167        if let Some(cache) = self.cache() {
168            cache.block_tx_hashes.lock().put(hash.clone(), ret.clone());
169        }
170
171        ret
172    }
173
174    /// Get proposal short id by block header hash
175    fn get_block_proposal_txs_ids(
176        &self,
177        hash: &packed::Byte32,
178    ) -> Option<packed::ProposalShortIdVec> {
179        if let Some(cache) = self.cache() {
180            if let Some(data) = cache.block_proposals.lock().get(hash) {
181                return Some(data.clone());
182            }
183        };
184
185        let ret = self
186            .get(COLUMN_BLOCK_PROPOSAL_IDS, hash.as_slice())
187            .map(|slice| {
188                packed::ProposalShortIdVecReader::from_slice_should_be_ok(slice.as_ref())
189                    .to_entity()
190            });
191
192        if let Some(cache) = self.cache() {
193            ret.inspect(|data| {
194                cache.block_proposals.lock().put(hash.clone(), data.clone());
195            })
196        } else {
197            ret
198        }
199    }
200
201    /// Get block uncles by block header hash
202    fn get_block_uncles(&self, hash: &packed::Byte32) -> Option<UncleBlockVecView> {
203        if let Some(cache) = self.cache() {
204            if let Some(data) = cache.block_uncles.lock().get(hash) {
205                return Some(data.clone());
206            }
207        };
208
209        let ret = self.get(COLUMN_BLOCK_UNCLE, hash.as_slice()).map(|slice| {
210            let reader = packed::UncleBlockVecViewReader::from_slice_should_be_ok(slice.as_ref());
211            Unpack::<UncleBlockVecView>::unpack(&reader)
212        });
213
214        if let Some(cache) = self.cache() {
215            ret.inspect(|uncles| {
216                cache.block_uncles.lock().put(hash.clone(), uncles.clone());
217            })
218        } else {
219            ret
220        }
221    }
222
223    /// Get block extension by block header hash
224    fn get_block_extension(&self, hash: &packed::Byte32) -> Option<packed::Bytes> {
225        if let Some(cache) = self.cache() {
226            if let Some(data) = cache.block_extensions.lock().get(hash) {
227                return data.clone();
228            }
229        };
230
231        let ret = self
232            .get(COLUMN_BLOCK_EXTENSION, hash.as_slice())
233            .map(|slice| packed::BytesReader::from_slice_should_be_ok(slice.as_ref()).to_entity());
234
235        if let Some(cache) = self.cache() {
236            cache.block_extensions.lock().put(hash.clone(), ret.clone());
237        }
238        ret
239    }
240
241    /// Get block ext by block header hash
242    ///
243    /// Since v0.106, `BlockExt` added two option fields, so we have to use compatibility mode to read
244    fn get_block_ext(&self, block_hash: &packed::Byte32) -> Option<BlockExt> {
245        self.get(COLUMN_BLOCK_EXT, block_hash.as_slice())
246            .map(|slice| {
247                let reader =
248                    packed::BlockExtReader::from_compatible_slice_should_be_ok(slice.as_ref());
249                match reader.count_extra_fields() {
250                    0 => reader.unpack(),
251                    2 => packed::BlockExtV1Reader::from_slice_should_be_ok(slice.as_ref()).unpack(),
252                    _ => {
253                        panic!(
254                            "BlockExt storage field count doesn't match, expect 7 or 5, actual {}",
255                            reader.field_count()
256                        )
257                    }
258                }
259            })
260    }
261
262    /// Get block header hash by block number
263    fn get_block_hash(&self, number: BlockNumber) -> Option<packed::Byte32> {
264        let block_number: packed::Uint64 = number.pack();
265        self.get(COLUMN_INDEX, block_number.as_slice())
266            .map(|raw| packed::Byte32Reader::from_slice_should_be_ok(raw.as_ref()).to_entity())
267    }
268
269    /// Get block number by block header hash
270    fn get_block_number(&self, hash: &packed::Byte32) -> Option<BlockNumber> {
271        self.get(COLUMN_INDEX, hash.as_slice())
272            .map(|raw| packed::Uint64Reader::from_slice_should_be_ok(raw.as_ref()).unpack())
273    }
274
275    /// TODO(doc): @quake
276    fn is_main_chain(&self, hash: &packed::Byte32) -> bool {
277        self.get(COLUMN_INDEX, hash.as_slice()).is_some()
278    }
279
280    /// TODO(doc): @quake
281    fn get_tip_header(&self) -> Option<HeaderView> {
282        self.get(COLUMN_META, META_TIP_HEADER_KEY)
283            .and_then(|raw| {
284                self.get_block_header(
285                    &packed::Byte32Reader::from_slice_should_be_ok(raw.as_ref()).to_entity(),
286                )
287            })
288            .map(Into::into)
289    }
290
291    /// Returns true if the transaction confirmed in main chain.
292    ///
293    /// This function is base on transaction index `COLUMN_TRANSACTION_INFO`.
294    /// Current release maintains a full index of historical transaction by default, this may be changed in future
295    fn transaction_exists(&self, hash: &packed::Byte32) -> bool {
296        self.get(COLUMN_TRANSACTION_INFO, hash.as_slice()).is_some()
297    }
298
299    /// Get commit transaction and block hash by its hash
300    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    /// TODO(doc): @quake
306    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                Unpack::<TransactionInfo>::unpack(&reader)
311            })
312    }
313
314    /// Gets transaction and associated info with correspond hash
315    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            if tx_info.block_number > 0 && tx_info.block_number < freezer.number() {
322                let raw_block = freezer
323                    .retrieve(tx_info.block_number)
324                    .expect("block frozen")?;
325                let raw_block_reader =
326                    packed::BlockReader::from_compatible_slice(&raw_block).expect("checked data");
327                let tx_reader = raw_block_reader.transactions().get(tx_info.index)?;
328                return Some((tx_reader.to_entity().into_view(), tx_info));
329            }
330        }
331        self.get(COLUMN_BLOCK_BODY, tx_info.key().as_slice())
332            .map(|slice| {
333                let reader = packed::TransactionViewReader::from_slice_should_be_ok(slice.as_ref());
334                (reader.unpack(), tx_info)
335            })
336    }
337
338    /// Return whether cell is live
339    fn have_cell(&self, out_point: &OutPoint) -> bool {
340        let key = out_point.to_cell_key();
341        self.get(COLUMN_CELL, &key).is_some()
342    }
343
344    /// Gets cell meta data with out_point
345    fn get_cell(&self, out_point: &OutPoint) -> Option<CellMeta> {
346        let key = out_point.to_cell_key();
347        self.get(COLUMN_CELL, &key).map(|slice| {
348            let reader = packed::CellEntryReader::from_slice_should_be_ok(slice.as_ref());
349            build_cell_meta_from_reader(out_point.clone(), reader)
350        })
351    }
352
353    /// TODO(doc): @quake
354    fn get_cell_data(&self, out_point: &OutPoint) -> Option<(Bytes, packed::Byte32)> {
355        let key = out_point.to_cell_key();
356        if let Some(cache) = self.cache() {
357            if let Some(cached) = cache.cell_data.lock().get(&key) {
358                return Some(cached.clone());
359            }
360        };
361
362        let ret = self.get(COLUMN_CELL_DATA, &key).map(|slice| {
363            if !slice.as_ref().is_empty() {
364                let reader = packed::CellDataEntryReader::from_slice_should_be_ok(slice.as_ref());
365                let data = reader.output_data().unpack();
366                let data_hash = reader.output_data_hash().to_entity();
367                (data, data_hash)
368            } else {
369                (Bytes::new(), packed::Byte32::zero())
370            }
371        });
372
373        if let Some(cache) = self.cache() {
374            ret.inspect(|cached| {
375                cache.cell_data.lock().put(key, cached.clone());
376            })
377        } else {
378            ret
379        }
380    }
381
382    /// TODO(doc): @quake
383    fn get_cell_data_hash(&self, out_point: &OutPoint) -> Option<packed::Byte32> {
384        let key = out_point.to_cell_key();
385        if let Some(cache) = self.cache() {
386            if let Some(cached) = cache.cell_data_hash.lock().get(&key) {
387                return Some(cached.clone());
388            }
389        };
390
391        let ret = self.get(COLUMN_CELL_DATA_HASH, &key).map(|raw| {
392            if !raw.as_ref().is_empty() {
393                packed::Byte32Reader::from_slice_should_be_ok(raw.as_ref()).to_entity()
394            } else {
395                packed::Byte32::zero()
396            }
397        });
398
399        if let Some(cache) = self.cache() {
400            ret.inspect(|cached| {
401                cache.cell_data_hash.lock().put(key, cached.clone());
402            })
403        } else {
404            ret
405        }
406    }
407
408    /// Gets current epoch ext
409    fn get_current_epoch_ext(&self) -> Option<EpochExt> {
410        self.get(COLUMN_META, META_CURRENT_EPOCH_KEY)
411            .map(|slice| packed::EpochExtReader::from_slice_should_be_ok(slice.as_ref()).unpack())
412    }
413
414    /// Gets epoch ext by epoch index
415    fn get_epoch_ext(&self, hash: &packed::Byte32) -> Option<EpochExt> {
416        self.get(COLUMN_EPOCH, hash.as_slice())
417            .map(|slice| packed::EpochExtReader::from_slice_should_be_ok(slice.as_ref()).unpack())
418    }
419
420    /// Gets epoch index by epoch number
421    fn get_epoch_index(&self, number: EpochNumber) -> Option<packed::Byte32> {
422        let epoch_number: packed::Uint64 = number.pack();
423        self.get(COLUMN_EPOCH, epoch_number.as_slice())
424            .map(|raw| packed::Byte32Reader::from_slice_should_be_ok(raw.as_ref()).to_entity())
425    }
426
427    /// Gets epoch index by block hash
428    fn get_block_epoch_index(&self, block_hash: &packed::Byte32) -> Option<packed::Byte32> {
429        self.get(COLUMN_BLOCK_EPOCH, block_hash.as_slice())
430            .map(|raw| packed::Byte32Reader::from_slice_should_be_ok(raw.as_ref()).to_entity())
431    }
432
433    /// TODO(doc): @quake
434    fn get_block_epoch(&self, hash: &packed::Byte32) -> Option<EpochExt> {
435        self.get_block_epoch_index(hash)
436            .and_then(|index| self.get_epoch_ext(&index))
437    }
438
439    /// TODO(doc): @quake
440    fn is_uncle(&self, hash: &packed::Byte32) -> bool {
441        self.get(COLUMN_UNCLES, hash.as_slice()).is_some()
442    }
443
444    /// Gets header by uncle header hash
445    fn get_uncle_header(&self, hash: &packed::Byte32) -> Option<HeaderView> {
446        self.get(COLUMN_UNCLES, hash.as_slice()).map(|slice| {
447            let reader = packed::HeaderViewReader::from_slice_should_be_ok(slice.as_ref());
448            Unpack::<HeaderView>::unpack(&reader)
449        })
450    }
451
452    /// TODO(doc): @quake
453    fn block_exists(&self, hash: &packed::Byte32) -> bool {
454        if let Some(cache) = self.cache() {
455            if cache.headers.lock().get(hash).is_some() {
456                return true;
457            }
458        };
459        self.get(COLUMN_BLOCK_HEADER, hash.as_slice()).is_some()
460    }
461
462    /// Gets cellbase by block hash
463    fn get_cellbase(&self, hash: &packed::Byte32) -> Option<TransactionView> {
464        let key = packed::TransactionKey::new_builder()
465            .block_hash(hash.to_owned())
466            .build();
467        self.get(COLUMN_BLOCK_BODY, key.as_slice()).map(|slice| {
468            let reader = packed::TransactionViewReader::from_slice_should_be_ok(slice.as_ref());
469            Unpack::<TransactionView>::unpack(&reader)
470        })
471    }
472
473    /// Gets latest built filter data block hash
474    fn get_latest_built_filter_data_block_hash(&self) -> Option<packed::Byte32> {
475        self.get(COLUMN_META, META_LATEST_BUILT_FILTER_DATA_KEY)
476            .map(|raw| packed::Byte32Reader::from_slice_should_be_ok(raw.as_ref()).to_entity())
477    }
478
479    /// Gets block filter data by block hash
480    fn get_block_filter(&self, hash: &packed::Byte32) -> Option<packed::Bytes> {
481        self.get(COLUMN_BLOCK_FILTER, hash.as_slice())
482            .map(|slice| packed::BytesReader::from_slice_should_be_ok(slice.as_ref()).to_entity())
483    }
484
485    /// Gets block filter hash by block hash
486    fn get_block_filter_hash(&self, hash: &packed::Byte32) -> Option<packed::Byte32> {
487        self.get(COLUMN_BLOCK_FILTER_HASH, hash.as_slice())
488            .map(|slice| packed::Byte32Reader::from_slice_should_be_ok(slice.as_ref()).to_entity())
489    }
490
491    /// Gets block bytes by block hash
492    fn get_packed_block(&self, hash: &packed::Byte32) -> Option<packed::Block> {
493        let header = self
494            .get(COLUMN_BLOCK_HEADER, hash.as_slice())
495            .map(|slice| {
496                let reader = packed::HeaderViewReader::from_slice_should_be_ok(slice.as_ref());
497                reader.data().to_entity()
498            })?;
499
500        let prefix = hash.as_slice();
501        let transactions: packed::TransactionVec = self
502            .get_iter(
503                COLUMN_BLOCK_BODY,
504                IteratorMode::From(prefix, Direction::Forward),
505            )
506            .take_while(|(key, _)| key.starts_with(prefix))
507            .map(|(_key, value)| {
508                let reader = packed::TransactionViewReader::from_slice_should_be_ok(value.as_ref());
509                reader.data().to_entity()
510            })
511            .pack();
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    /// Gets block header bytes by block hash
539    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    /// Gets a header digest.
547    fn get_header_digest(&self, position_u64: u64) -> Option<packed::HeaderDigest> {
548        let position: packed::Uint64 = position_u64.pack();
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    /// Gets ancestor block header by a base block hash and number
557    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().unpack(),
578            block_hash: reader.block_hash().to_entity(),
579            block_epoch: reader.block_epoch().unpack(),
580            index: reader.index().unpack(),
581        }),
582        data_bytes: reader.data_size().unpack(),
583        mem_cell_data: None,
584        mem_cell_data_hash: None,
585    }
586}