ckb_store/
store.rs

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
26/// The `ChainStore` trait provides chain data store interface
27pub trait ChainStore: Send + Sync + Sized {
28    /// Return cache reference
29    fn cache(&self) -> Option<&StoreCache>;
30    /// Return freezer reference
31    fn freezer(&self) -> Option<&Freezer>;
32    /// Return the bytes associated with a key value and the given column family.
33    fn get(&self, col: Col, key: &[u8]) -> Option<DBPinnableSlice>;
34    /// Return an iterator over the database key-value pairs in the given column family.
35    fn get_iter(&self, col: Col, mode: IteratorMode) -> DBIter;
36    /// Return the borrowed data loader wrapper
37    fn borrow_as_data_loader(&self) -> BorrowedDataLoaderWrapper<Self> {
38        BorrowedDataLoaderWrapper::new(self)
39    }
40
41    /// Get block by block header hash
42    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    /// Get header by block header hash
71    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    /// Get block body by block header hash
92    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    /// Get unfrozen block from ky-store with given hash
107    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    /// Get all transaction-hashes in block body by block header hash
148    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    /// Get proposal short id by block header hash
176    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    /// Get block uncles by block header hash
203    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    /// Get block extension by block header hash
225    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    /// Get block ext by block header hash
243    ///
244    /// Since v0.106, `BlockExt` added two option fields, so we have to use compatibility mode to read
245    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    /// Get block header hash by block number
264    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    /// Get block number by block header hash
271    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    /// TODO(doc): @quake
277    fn is_main_chain(&self, hash: &packed::Byte32) -> bool {
278        self.get(COLUMN_INDEX, hash.as_slice()).is_some()
279    }
280
281    /// TODO(doc): @quake
282    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    /// Returns true if the transaction confirmed in main chain.
291    ///
292    /// This function is base on transaction index `COLUMN_TRANSACTION_INFO`.
293    /// Current release maintains a full index of historical transaction by default, this may be changed in future
294    fn transaction_exists(&self, hash: &packed::Byte32) -> bool {
295        self.get(COLUMN_TRANSACTION_INFO, hash.as_slice()).is_some()
296    }
297
298    /// Get commit transaction and block hash by its hash
299    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    /// TODO(doc): @quake
305    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    /// Gets transaction and associated info with correspond hash
314    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    /// Return whether cell is live
338    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    /// Gets cell meta data with out_point
344    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    /// TODO(doc): @quake
353    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    /// TODO(doc): @quake
382    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    /// Gets current epoch ext
408    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    /// Gets epoch ext by epoch index
414    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    /// Gets epoch index by epoch number
420    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    /// Gets epoch index by block hash
427    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    /// TODO(doc): @quake
433    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    /// TODO(doc): @quake
439    fn is_uncle(&self, hash: &packed::Byte32) -> bool {
440        self.get(COLUMN_UNCLES, hash.as_slice()).is_some()
441    }
442
443    /// Gets header by uncle header hash
444    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    /// TODO(doc): @quake
452    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    /// Gets cellbase by block hash
462    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    /// Gets latest built filter data block hash
473    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    /// Gets block filter data by block hash
479    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    /// Gets block filter hash by block hash
485    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    /// Gets block bytes by block hash
491    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    /// 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.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    /// 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().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}