1use crate::cache::StoreCache;
2use crate::store::ChainStore;
3use ckb_chain_spec::versionbits::VersionbitsIndexer;
4use ckb_db::{
5 DBPinnableSlice, RocksDBTransaction, RocksDBTransactionSnapshot,
6 iter::{DBIter, DBIterator, IteratorMode},
7};
8use ckb_db_schema::{
9 COLUMN_BLOCK_BODY, COLUMN_BLOCK_EPOCH, COLUMN_BLOCK_EXT, COLUMN_BLOCK_EXTENSION,
10 COLUMN_BLOCK_FILTER, COLUMN_BLOCK_FILTER_HASH, COLUMN_BLOCK_HEADER, COLUMN_BLOCK_PROPOSAL_IDS,
11 COLUMN_BLOCK_UNCLE, COLUMN_CELL, COLUMN_CELL_DATA, COLUMN_CELL_DATA_HASH,
12 COLUMN_CHAIN_ROOT_MMR, COLUMN_EPOCH, COLUMN_INDEX, COLUMN_META, COLUMN_NUMBER_HASH,
13 COLUMN_TRANSACTION_INFO, COLUMN_UNCLES, Col, META_CURRENT_EPOCH_KEY,
14 META_LATEST_BUILT_FILTER_DATA_KEY, META_TIP_HEADER_KEY,
15};
16use ckb_error::Error;
17use ckb_freezer::Freezer;
18use ckb_merkle_mountain_range::{Error as MMRError, MMRStore, Result as MMRResult};
19use ckb_types::{
20 core::{
21 BlockExt, BlockView, EpochExt, HeaderView, TransactionView,
22 cell::{CellChecker, CellProvider, CellStatus},
23 },
24 packed::{self, Byte32, OutPoint},
25 prelude::*,
26 utilities::calc_filter_hash,
27};
28use std::sync::Arc;
29
30pub struct StoreTransaction {
32 pub(crate) inner: RocksDBTransaction,
33 pub(crate) freezer: Option<Freezer>,
34 pub(crate) cache: Arc<StoreCache>,
35}
36
37impl ChainStore for StoreTransaction {
38 fn cache(&self) -> Option<&StoreCache> {
39 Some(&self.cache)
40 }
41
42 fn freezer(&self) -> Option<&Freezer> {
43 self.freezer.as_ref()
44 }
45
46 fn get(&self, col: Col, key: &[u8]) -> Option<DBPinnableSlice<'_>> {
47 self.inner
48 .get_pinned(col, key)
49 .expect("db operation should be ok")
50 }
51
52 fn get_iter(&self, col: Col, mode: IteratorMode) -> DBIter<'_> {
53 self.inner
54 .iter(col, mode)
55 .expect("db operation should be ok")
56 }
57}
58
59impl VersionbitsIndexer for StoreTransaction {
60 fn block_epoch_index(&self, block_hash: &Byte32) -> Option<Byte32> {
61 ChainStore::get_block_epoch_index(self, block_hash)
62 }
63
64 fn epoch_ext(&self, index: &Byte32) -> Option<EpochExt> {
65 ChainStore::get_epoch_ext(self, index)
66 }
67
68 fn block_header(&self, block_hash: &Byte32) -> Option<HeaderView> {
69 ChainStore::get_block_header(self, block_hash)
70 }
71
72 fn cellbase(&self, block_hash: &Byte32) -> Option<TransactionView> {
73 ChainStore::get_cellbase(self, block_hash)
74 }
75}
76
77impl CellProvider for StoreTransaction {
78 fn cell(&self, out_point: &OutPoint, eager_load: bool) -> CellStatus {
79 match self.get_cell(out_point) {
80 Some(mut cell_meta) => {
81 if eager_load && let Some((data, data_hash)) = self.get_cell_data(out_point) {
82 cell_meta.mem_cell_data = Some(data);
83 cell_meta.mem_cell_data_hash = Some(data_hash);
84 }
85 CellStatus::live_cell(cell_meta)
86 }
87 None => CellStatus::Unknown,
88 }
89 }
90}
91
92impl CellChecker for StoreTransaction {
93 fn is_live(&self, out_point: &OutPoint) -> Option<bool> {
94 if self.have_cell(out_point) {
95 Some(true)
96 } else {
97 None
98 }
99 }
100}
101
102pub struct StoreTransactionSnapshot<'a> {
103 pub(crate) inner: RocksDBTransactionSnapshot<'a>,
104 pub(crate) freezer: Option<Freezer>,
105 pub(crate) cache: Arc<StoreCache>,
106}
107
108impl<'a> ChainStore for StoreTransactionSnapshot<'a> {
109 fn cache(&self) -> Option<&StoreCache> {
110 Some(&self.cache)
111 }
112
113 fn freezer(&self) -> Option<&Freezer> {
114 self.freezer.as_ref()
115 }
116
117 fn get(&self, col: Col, key: &[u8]) -> Option<DBPinnableSlice<'_>> {
118 self.inner
119 .get_pinned(col, key)
120 .expect("db operation should be ok")
121 }
122
123 fn get_iter(&self, col: Col, mode: IteratorMode) -> DBIter<'_> {
124 self.inner
125 .iter(col, mode)
126 .expect("db operation should be ok")
127 }
128}
129
130impl StoreTransaction {
131 pub fn insert_raw(&self, col: Col, key: &[u8], value: &[u8]) -> Result<(), Error> {
133 self.inner.put(col, key, value)
134 }
135
136 pub fn delete(&self, col: Col, key: &[u8]) -> Result<(), Error> {
138 self.inner.delete(col, key)
139 }
140
141 pub fn commit(&self) -> Result<(), Error> {
143 self.inner.commit()
144 }
145
146 pub fn get_snapshot(&self) -> StoreTransactionSnapshot<'_> {
148 StoreTransactionSnapshot {
149 inner: self.inner.get_snapshot(),
150 freezer: self.freezer.clone(),
151 cache: Arc::clone(&self.cache),
152 }
153 }
154
155 pub fn get_update_for_tip_hash(
157 &self,
158 snapshot: &StoreTransactionSnapshot<'_>,
159 ) -> Option<packed::Byte32> {
160 self.inner
161 .get_for_update(COLUMN_META, META_TIP_HEADER_KEY, &snapshot.inner)
162 .expect("db operation should be ok")
163 .map(|slice| packed::Byte32Reader::from_slice_should_be_ok(slice.as_ref()).to_entity())
164 }
165
166 pub fn insert_tip_header(&self, h: &HeaderView) -> Result<(), Error> {
168 self.insert_raw(COLUMN_META, META_TIP_HEADER_KEY, h.hash().as_slice())
169 }
170
171 pub fn insert_block(&self, block: &BlockView) -> Result<(), Error> {
173 let hash = block.hash();
174 let header = Into::<packed::HeaderView>::into(block.header());
175 let uncles = Into::<packed::UncleBlockVecView>::into(block.uncles());
176 let proposals = block.data().proposals();
177 let txs_len: packed::Uint32 = (block.transactions().len() as u32).into();
178 self.insert_raw(COLUMN_BLOCK_HEADER, hash.as_slice(), header.as_slice())?;
179 self.insert_raw(COLUMN_BLOCK_UNCLE, hash.as_slice(), uncles.as_slice())?;
180 if let Some(extension) = block.extension() {
181 self.insert_raw(
182 COLUMN_BLOCK_EXTENSION,
183 hash.as_slice(),
184 extension.as_slice(),
185 )?;
186 }
187 self.insert_raw(
188 COLUMN_NUMBER_HASH,
189 packed::NumberHash::new_builder()
190 .number(block.number())
191 .block_hash(hash.clone())
192 .build()
193 .as_slice(),
194 txs_len.as_slice(),
195 )?;
196 self.insert_raw(
197 COLUMN_BLOCK_PROPOSAL_IDS,
198 hash.as_slice(),
199 proposals.as_slice(),
200 )?;
201 for (index, tx) in block.transactions().into_iter().enumerate() {
202 let key = packed::TransactionKey::new_builder()
203 .block_hash(hash.clone())
204 .index(index)
205 .build();
206 let tx_data = Into::<packed::TransactionView>::into(tx);
207 self.insert_raw(COLUMN_BLOCK_BODY, key.as_slice(), tx_data.as_slice())?;
208 }
209 Ok(())
210 }
211
212 pub fn delete_block(&self, block: &BlockView) -> Result<(), Error> {
214 let hash = block.hash();
215 let txs_len = block.transactions().len();
216 self.delete(COLUMN_BLOCK_HEADER, hash.as_slice())?;
217 self.delete(COLUMN_BLOCK_UNCLE, hash.as_slice())?;
218 self.delete(COLUMN_BLOCK_EXTENSION, hash.as_slice())?;
219 self.delete(COLUMN_BLOCK_PROPOSAL_IDS, hash.as_slice())?;
220 self.delete(
221 COLUMN_NUMBER_HASH,
222 packed::NumberHash::new_builder()
223 .number(block.number())
224 .block_hash(hash.clone())
225 .build()
226 .as_slice(),
227 )?;
228 for index in 0..txs_len {
231 let key = packed::TransactionKey::new_builder()
232 .block_hash(hash.clone())
233 .index(index)
234 .build();
235 self.delete(COLUMN_BLOCK_BODY, key.as_slice())?;
236 }
237 Ok(())
238 }
239
240 pub fn insert_block_ext(
242 &self,
243 block_hash: &packed::Byte32,
244 ext: &BlockExt,
245 ) -> Result<(), Error> {
246 let packed_ext: packed::BlockExtV1 = ext.into();
247 self.insert_raw(
248 COLUMN_BLOCK_EXT,
249 block_hash.as_slice(),
250 packed_ext.as_slice(),
251 )
252 }
253
254 pub fn attach_block(&self, block: &BlockView) -> Result<(), Error> {
256 let header = block.data().header();
257 let block_hash = block.hash();
258 for (index, tx_hash) in block.tx_hashes().iter().enumerate() {
259 let key = packed::TransactionKey::new_builder()
260 .block_hash(block_hash.clone())
261 .index(index)
262 .build();
263 let info = packed::TransactionInfo::new_builder()
264 .key(key)
265 .block_number(header.raw().number())
266 .block_epoch(header.raw().epoch())
267 .build();
268 self.insert_raw(COLUMN_TRANSACTION_INFO, tx_hash.as_slice(), info.as_slice())?;
269 }
270 let block_number: packed::Uint64 = block.number().into();
271 self.insert_raw(COLUMN_INDEX, block_number.as_slice(), block_hash.as_slice())?;
272 for uncle in block.uncles().into_iter() {
273 self.insert_raw(
274 COLUMN_UNCLES,
275 uncle.hash().as_slice(),
276 Into::<packed::HeaderView>::into(uncle.header()).as_slice(),
277 )?;
278 }
279 self.insert_raw(COLUMN_INDEX, block_hash.as_slice(), block_number.as_slice())
280 }
281
282 pub fn detach_block(&self, block: &BlockView) -> Result<(), Error> {
284 for tx_hash in block.tx_hashes().iter() {
285 self.delete(COLUMN_TRANSACTION_INFO, tx_hash.as_slice())?;
286 }
287 for uncle in block.uncles().into_iter() {
288 self.delete(COLUMN_UNCLES, uncle.hash().as_slice())?;
289 }
290 let block_number = block.data().header().raw().number();
291 self.delete(COLUMN_INDEX, block_number.as_slice())?;
292 self.delete(COLUMN_INDEX, block.hash().as_slice())
293 }
294
295 pub fn insert_block_epoch_index(
297 &self,
298 block_hash: &packed::Byte32,
299 epoch_hash: &packed::Byte32,
300 ) -> Result<(), Error> {
301 self.insert_raw(
302 COLUMN_BLOCK_EPOCH,
303 block_hash.as_slice(),
304 epoch_hash.as_slice(),
305 )
306 }
307
308 pub fn insert_epoch_ext(&self, hash: &packed::Byte32, epoch: &EpochExt) -> Result<(), Error> {
310 self.insert_raw(
311 COLUMN_EPOCH,
312 hash.as_slice(),
313 Into::<packed::EpochExt>::into(epoch).as_slice(),
314 )?;
315 let epoch_number: packed::Uint64 = epoch.number().into();
316 self.insert_raw(COLUMN_EPOCH, epoch_number.as_slice(), hash.as_slice())
317 }
318
319 pub fn insert_current_epoch_ext(&self, epoch: &EpochExt) -> Result<(), Error> {
321 self.insert_raw(
322 COLUMN_META,
323 META_CURRENT_EPOCH_KEY,
324 Into::<packed::EpochExt>::into(epoch).as_slice(),
325 )
326 }
327
328 pub fn insert_cells(
330 &self,
331 cells: impl Iterator<
332 Item = (
333 packed::OutPoint,
334 packed::CellEntry,
335 Option<packed::CellDataEntry>,
336 ),
337 >,
338 ) -> Result<(), Error> {
339 for (out_point, cell, cell_data) in cells {
340 let key = out_point.to_cell_key();
341 self.insert_raw(COLUMN_CELL, &key, cell.as_slice())?;
342 if let Some(data) = cell_data {
343 self.insert_raw(COLUMN_CELL_DATA, &key, data.as_slice())?;
344 self.insert_raw(
345 COLUMN_CELL_DATA_HASH,
346 &key,
347 data.output_data_hash().as_slice(),
348 )?;
349 } else {
350 self.insert_raw(COLUMN_CELL_DATA, &key, &[])?;
351 self.insert_raw(COLUMN_CELL_DATA_HASH, &key, &[])?;
352 }
353 }
354 Ok(())
355 }
356
357 pub fn delete_cells(
359 &self,
360 out_points: impl Iterator<Item = packed::OutPoint>,
361 ) -> Result<(), Error> {
362 for out_point in out_points {
363 let key = out_point.to_cell_key();
364 self.delete(COLUMN_CELL, &key)?;
365 self.delete(COLUMN_CELL_DATA, &key)?;
366 self.delete(COLUMN_CELL_DATA_HASH, &key)?;
367 }
368 Ok(())
369 }
370
371 pub fn insert_header_digest(
373 &self,
374 position_u64: u64,
375 header_digest: &packed::HeaderDigest,
376 ) -> Result<(), Error> {
377 let position: packed::Uint64 = position_u64.into();
378 self.insert_raw(
379 COLUMN_CHAIN_ROOT_MMR,
380 position.as_slice(),
381 header_digest.as_slice(),
382 )
383 }
384
385 pub fn delete_header_digest(&self, position_u64: u64) -> Result<(), Error> {
387 let position: packed::Uint64 = position_u64.into();
388 self.delete(COLUMN_CHAIN_ROOT_MMR, position.as_slice())
389 }
390
391 pub fn insert_block_filter(
393 &self,
394 block_hash: &packed::Byte32,
395 filter_data: &packed::Bytes,
396 parent_block_filter_hash: &packed::Byte32,
397 ) -> Result<(), Error> {
398 self.insert_raw(
399 COLUMN_BLOCK_FILTER,
400 block_hash.as_slice(),
401 filter_data.as_slice(),
402 )?;
403 let current_block_filter_hash = calc_filter_hash(parent_block_filter_hash, filter_data);
404 self.insert_raw(
405 COLUMN_BLOCK_FILTER_HASH,
406 block_hash.as_slice(),
407 current_block_filter_hash.as_slice(),
408 )?;
409 self.insert_raw(
410 COLUMN_META,
411 META_LATEST_BUILT_FILTER_DATA_KEY,
412 block_hash.as_slice(),
413 )
414 }
415}
416
417impl MMRStore<packed::HeaderDigest> for &StoreTransaction {
418 fn get_elem(&self, pos: u64) -> MMRResult<Option<packed::HeaderDigest>> {
419 Ok(self.get_header_digest(pos))
420 }
421
422 fn append(&mut self, pos: u64, elems: Vec<packed::HeaderDigest>) -> MMRResult<()> {
423 for (offset, elem) in elems.iter().enumerate() {
424 let pos: u64 = pos + (offset as u64);
425 self.insert_header_digest(pos, elem).map_err(|err| {
426 MMRError::StoreError(format!("Failed to append to MMR, DB error {err}"))
427 })?;
428 }
429 Ok(())
430 }
431}