1use std::{
16 collections::{BTreeMap, HashMap},
17 sync::Arc,
18};
19
20use zebra_chain::{
21 block::Height,
22 ironwood, orchard,
23 parallel::tree::NoteCommitmentTrees,
24 parameters::NetworkUpgrade,
25 sapling, sprout,
26 subtree::{NoteCommitmentSubtreeData, NoteCommitmentSubtreeIndex},
27 transaction::Transaction,
28};
29
30use crate::{
31 request::{FinalizedBlock, Treestate},
32 service::finalized_state::{
33 disk_db::{DiskWriteBatch, ReadDisk, WriteDisk},
34 disk_format::RawBytes,
35 zebra_db::ZebraDb,
36 },
37 TransactionLocation,
38};
39
40#[allow(unused_imports)]
42use zebra_chain::subtree::NoteCommitmentSubtree;
43
44impl ZebraDb {
45 pub fn contains_sprout_nullifier(&self, sprout_nullifier: &sprout::Nullifier) -> bool {
49 let sprout_nullifiers = self.db.cf_handle("sprout_nullifiers").unwrap();
50 self.db.zs_contains(&sprout_nullifiers, &sprout_nullifier)
51 }
52
53 pub fn contains_sapling_nullifier(&self, sapling_nullifier: &sapling::Nullifier) -> bool {
55 let sapling_nullifiers = self.db.cf_handle("sapling_nullifiers").unwrap();
56 self.db.zs_contains(&sapling_nullifiers, &sapling_nullifier)
57 }
58
59 pub fn contains_orchard_nullifier(&self, orchard_nullifier: &orchard::Nullifier) -> bool {
61 let orchard_nullifiers = self.db.cf_handle("orchard_nullifiers").unwrap();
62 self.db.zs_contains(&orchard_nullifiers, &orchard_nullifier)
63 }
64
65 pub fn contains_ironwood_nullifier(&self, ironwood_nullifier: &ironwood::Nullifier) -> bool {
67 let ironwood_nullifiers = self.db.cf_handle("ironwood_nullifiers").unwrap();
68 self.db
69 .zs_contains(&ironwood_nullifiers, &ironwood_nullifier)
70 }
71
72 #[allow(clippy::unwrap_in_result)]
76 pub fn sprout_revealing_tx_loc(
77 &self,
78 sprout_nullifier: &sprout::Nullifier,
79 ) -> Option<TransactionLocation> {
80 let sprout_nullifiers = self.db.cf_handle("sprout_nullifiers").unwrap();
81 self.db.zs_get(&sprout_nullifiers, &sprout_nullifier)?
82 }
83
84 #[allow(clippy::unwrap_in_result)]
88 pub fn sapling_revealing_tx_loc(
89 &self,
90 sapling_nullifier: &sapling::Nullifier,
91 ) -> Option<TransactionLocation> {
92 let sapling_nullifiers = self.db.cf_handle("sapling_nullifiers").unwrap();
93 self.db.zs_get(&sapling_nullifiers, &sapling_nullifier)?
94 }
95
96 #[allow(clippy::unwrap_in_result)]
100 pub fn orchard_revealing_tx_loc(
101 &self,
102 orchard_nullifier: &orchard::Nullifier,
103 ) -> Option<TransactionLocation> {
104 let orchard_nullifiers = self.db.cf_handle("orchard_nullifiers").unwrap();
105 self.db.zs_get(&orchard_nullifiers, &orchard_nullifier)?
106 }
107
108 #[allow(clippy::unwrap_in_result)]
112 pub fn ironwood_revealing_tx_loc(
113 &self,
114 ironwood_nullifier: &ironwood::Nullifier,
115 ) -> Option<TransactionLocation> {
116 let ironwood_nullifiers = self.db.cf_handle("ironwood_nullifiers").unwrap();
117 self.db.zs_get(&ironwood_nullifiers, &ironwood_nullifier)?
118 }
119
120 #[allow(dead_code)]
122 pub fn contains_sprout_anchor(&self, sprout_anchor: &sprout::tree::Root) -> bool {
123 let sprout_anchors = self.db.cf_handle("sprout_anchors").unwrap();
124 self.db.zs_contains(&sprout_anchors, &sprout_anchor)
125 }
126
127 pub fn contains_sapling_anchor(&self, sapling_anchor: &sapling::tree::Root) -> bool {
129 let sapling_anchors = self.db.cf_handle("sapling_anchors").unwrap();
130 self.db.zs_contains(&sapling_anchors, &sapling_anchor)
131 }
132
133 pub fn contains_orchard_anchor(&self, orchard_anchor: &orchard::tree::Root) -> bool {
135 let orchard_anchors = self.db.cf_handle("orchard_anchors").unwrap();
136 self.db.zs_contains(&orchard_anchors, &orchard_anchor)
137 }
138
139 pub fn contains_ironwood_anchor(&self, ironwood_anchor: &orchard::tree::Root) -> bool {
143 let ironwood_anchors = self.db.cf_handle("ironwood_anchors").unwrap();
144 self.db.zs_contains(&ironwood_anchors, &ironwood_anchor)
145 }
146
147 pub fn sprout_tree_for_tip(&self) -> Arc<sprout::tree::NoteCommitmentTree> {
152 if self.is_empty() {
153 return Arc::<sprout::tree::NoteCommitmentTree>::default();
154 }
155
156 let sprout_tree_cf = self.db.cf_handle("sprout_note_commitment_tree").unwrap();
157
158 let mut sprout_tree: Option<Arc<sprout::tree::NoteCommitmentTree>> =
173 self.db.zs_get(&sprout_tree_cf, &());
174
175 if sprout_tree.is_none() {
176 sprout_tree = self
180 .db
181 .zs_last_key_value(&sprout_tree_cf)
182 .map(|(_key, tree_value): (Height, _)| tree_value);
183 }
184
185 sprout_tree.expect("Sprout note commitment tree must exist if there is a finalized tip")
186 }
187
188 #[allow(clippy::unwrap_in_result)]
192 pub fn sprout_tree_by_anchor(
193 &self,
194 sprout_anchor: &sprout::tree::Root,
195 ) -> Option<Arc<sprout::tree::NoteCommitmentTree>> {
196 let sprout_anchors_handle = self.db.cf_handle("sprout_anchors").unwrap();
197
198 self.db
199 .zs_get(&sprout_anchors_handle, sprout_anchor)
200 .map(Arc::new)
201 }
202
203 #[allow(dead_code)]
207 pub fn sprout_trees_full_map(
208 &self,
209 ) -> HashMap<sprout::tree::Root, Arc<sprout::tree::NoteCommitmentTree>> {
210 let sprout_anchors_handle = self.db.cf_handle("sprout_anchors").unwrap();
211
212 self.db
213 .zs_items_in_range_unordered(&sprout_anchors_handle, ..)
214 }
215
216 pub fn sprout_trees_full_tip(
219 &self,
220 ) -> impl Iterator<Item = (RawBytes, Arc<sprout::tree::NoteCommitmentTree>)> + '_ {
221 let sprout_trees = self.db.cf_handle("sprout_note_commitment_tree").unwrap();
222 self.db.zs_forward_range_iter(&sprout_trees, ..)
223 }
224
225 pub fn sapling_tree_for_tip(&self) -> Arc<sapling::tree::NoteCommitmentTree> {
230 let height = match self.finalized_tip_height() {
231 Some(h) => h,
232 None => return Default::default(),
233 };
234
235 self.sapling_tree_by_height(&height)
236 .expect("Sapling note commitment tree must exist if there is a finalized tip")
237 }
238
239 #[allow(clippy::unwrap_in_result)]
242 pub fn sapling_tree_by_height(
243 &self,
244 height: &Height,
245 ) -> Option<Arc<sapling::tree::NoteCommitmentTree>> {
246 let tip_height = self.finalized_tip_height()?;
247
248 if *height > tip_height {
251 return None;
252 }
253
254 let sapling_trees = self.db.cf_handle("sapling_note_commitment_tree").unwrap();
255
256 let (_first_duplicate_height, tree) = self
258 .db
259 .zs_prev_key_value_back_from(&sapling_trees, height)
260 .expect(
261 "Sapling note commitment trees must exist for all heights below the finalized tip",
262 );
263
264 Some(Arc::new(tree))
265 }
266
267 pub fn sapling_tree_by_height_range<R>(
269 &self,
270 range: R,
271 ) -> impl Iterator<Item = (Height, Arc<sapling::tree::NoteCommitmentTree>)> + '_
272 where
273 R: std::ops::RangeBounds<Height>,
274 {
275 let sapling_trees = self.db.cf_handle("sapling_note_commitment_tree").unwrap();
276 self.db.zs_forward_range_iter(&sapling_trees, range)
277 }
278
279 pub fn sapling_tree_by_reversed_height_range<R>(
281 &self,
282 range: R,
283 ) -> impl Iterator<Item = (Height, Arc<sapling::tree::NoteCommitmentTree>)> + '_
284 where
285 R: std::ops::RangeBounds<Height>,
286 {
287 let sapling_trees = self.db.cf_handle("sapling_note_commitment_tree").unwrap();
288 self.db.zs_reverse_range_iter(&sapling_trees, range)
289 }
290
291 #[allow(clippy::unwrap_in_result)]
299 pub(in super::super) fn sapling_subtree_by_index(
300 &self,
301 index: impl Into<NoteCommitmentSubtreeIndex> + Copy,
302 ) -> Option<NoteCommitmentSubtree<sapling_crypto::Node>> {
303 let sapling_subtrees = self
304 .db
305 .cf_handle("sapling_note_commitment_subtree")
306 .unwrap();
307
308 let subtree_data: NoteCommitmentSubtreeData<sapling_crypto::Node> =
309 self.db.zs_get(&sapling_subtrees, &index.into())?;
310
311 Some(subtree_data.with_index(index))
312 }
313
314 #[allow(clippy::unwrap_in_result)]
316 pub fn sapling_subtree_list_by_index_range(
317 &self,
318 range: impl std::ops::RangeBounds<NoteCommitmentSubtreeIndex>,
319 ) -> BTreeMap<NoteCommitmentSubtreeIndex, NoteCommitmentSubtreeData<sapling_crypto::Node>> {
320 let sapling_subtrees = self
321 .db
322 .cf_handle("sapling_note_commitment_subtree")
323 .unwrap();
324
325 self.db
326 .zs_forward_range_iter(&sapling_subtrees, range)
327 .collect()
328 }
329
330 #[allow(clippy::unwrap_in_result)]
332 fn sapling_subtree_for_tip(&self) -> Option<NoteCommitmentSubtree<sapling_crypto::Node>> {
333 let sapling_subtrees = self
334 .db
335 .cf_handle("sapling_note_commitment_subtree")
336 .unwrap();
337
338 let (index, subtree_data): (
339 NoteCommitmentSubtreeIndex,
340 NoteCommitmentSubtreeData<sapling_crypto::Node>,
341 ) = self.db.zs_last_key_value(&sapling_subtrees)?;
342
343 let tip_height = self.finalized_tip_height()?;
344 if subtree_data.end_height != tip_height {
345 return None;
346 }
347
348 Some(subtree_data.with_index(index))
349 }
350
351 pub fn orchard_tree_for_tip(&self) -> Arc<orchard::tree::NoteCommitmentTree> {
356 let height = match self.finalized_tip_height() {
357 Some(h) => h,
358 None => return Default::default(),
359 };
360
361 self.orchard_tree_by_height(&height)
362 .expect("Orchard note commitment tree must exist if there is a finalized tip")
363 }
364
365 #[allow(clippy::unwrap_in_result)]
368 pub fn orchard_tree_by_height(
369 &self,
370 height: &Height,
371 ) -> Option<Arc<orchard::tree::NoteCommitmentTree>> {
372 let tip_height = self.finalized_tip_height()?;
373
374 if *height > tip_height {
377 return None;
378 }
379
380 let orchard_trees = self.db.cf_handle("orchard_note_commitment_tree").unwrap();
381
382 let (_first_duplicate_height, tree) = self
384 .db
385 .zs_prev_key_value_back_from(&orchard_trees, height)
386 .expect(
387 "Orchard note commitment trees must exist for all heights below the finalized tip",
388 );
389
390 Some(Arc::new(tree))
391 }
392
393 fn tree_by_height_range<R>(
399 &self,
400 cf: &str,
401 range: R,
402 ) -> impl Iterator<Item = (Height, Arc<orchard::tree::NoteCommitmentTree>)> + '_
403 where
404 R: std::ops::RangeBounds<Height>,
405 {
406 let trees = self.db.cf_handle(cf).unwrap();
407 self.db.zs_forward_range_iter(&trees, range)
408 }
409
410 fn subtree_list_by_index_range(
412 &self,
413 cf: &str,
414 range: impl std::ops::RangeBounds<NoteCommitmentSubtreeIndex>,
415 ) -> BTreeMap<NoteCommitmentSubtreeIndex, NoteCommitmentSubtreeData<orchard::tree::Node>> {
416 let subtrees = self.db.cf_handle(cf).unwrap();
417 self.db.zs_forward_range_iter(&subtrees, range).collect()
418 }
419
420 #[allow(clippy::unwrap_in_result)]
422 fn subtree_for_tip(&self, cf: &str) -> Option<NoteCommitmentSubtree<orchard::tree::Node>> {
423 let subtrees = self.db.cf_handle(cf).unwrap();
424
425 let (index, subtree_data): (
426 NoteCommitmentSubtreeIndex,
427 NoteCommitmentSubtreeData<orchard::tree::Node>,
428 ) = self.db.zs_last_key_value(&subtrees)?;
429
430 let tip_height = self.finalized_tip_height()?;
431 if subtree_data.end_height != tip_height {
432 return None;
433 }
434
435 Some(subtree_data.with_index(index))
436 }
437
438 pub fn orchard_tree_by_height_range<R>(
440 &self,
441 range: R,
442 ) -> impl Iterator<Item = (Height, Arc<orchard::tree::NoteCommitmentTree>)> + '_
443 where
444 R: std::ops::RangeBounds<Height>,
445 {
446 self.tree_by_height_range("orchard_note_commitment_tree", range)
447 }
448
449 pub fn orchard_tree_by_reversed_height_range<R>(
451 &self,
452 range: R,
453 ) -> impl Iterator<Item = (Height, Arc<orchard::tree::NoteCommitmentTree>)> + '_
454 where
455 R: std::ops::RangeBounds<Height>,
456 {
457 let orchard_trees = self.db.cf_handle("orchard_note_commitment_tree").unwrap();
458 self.db.zs_reverse_range_iter(&orchard_trees, range)
459 }
460
461 #[allow(clippy::unwrap_in_result)]
469 pub(in super::super) fn orchard_subtree_by_index(
470 &self,
471 index: impl Into<NoteCommitmentSubtreeIndex> + Copy,
472 ) -> Option<NoteCommitmentSubtree<orchard::tree::Node>> {
473 let orchard_subtrees = self
474 .db
475 .cf_handle("orchard_note_commitment_subtree")
476 .unwrap();
477
478 let subtree_data: NoteCommitmentSubtreeData<orchard::tree::Node> =
479 self.db.zs_get(&orchard_subtrees, &index.into())?;
480
481 Some(subtree_data.with_index(index))
482 }
483
484 pub fn orchard_subtree_list_by_index_range(
486 &self,
487 range: impl std::ops::RangeBounds<NoteCommitmentSubtreeIndex>,
488 ) -> BTreeMap<NoteCommitmentSubtreeIndex, NoteCommitmentSubtreeData<orchard::tree::Node>> {
489 self.subtree_list_by_index_range("orchard_note_commitment_subtree", range)
490 }
491
492 fn orchard_subtree_for_tip(&self) -> Option<NoteCommitmentSubtree<orchard::tree::Node>> {
494 self.subtree_for_tip("orchard_note_commitment_subtree")
495 }
496
497 pub fn ironwood_tree_for_tip(&self) -> Arc<orchard::tree::NoteCommitmentTree> {
505 let height = match self.finalized_tip_height() {
506 Some(h) => h,
507 None => return Default::default(),
508 };
509
510 self.ironwood_tree_by_height(&height)
511 .expect("Ironwood note commitment tree must exist if there is a finalized tip")
512 }
513
514 #[allow(clippy::unwrap_in_result)]
517 pub fn ironwood_tree_by_height(
518 &self,
519 height: &Height,
520 ) -> Option<Arc<orchard::tree::NoteCommitmentTree>> {
521 let tip_height = self.finalized_tip_height()?;
522
523 if *height > tip_height {
526 return None;
527 }
528
529 let ironwood_trees = self.db.cf_handle("ironwood_note_commitment_tree").unwrap();
530
531 let nu6_3_activated = NetworkUpgrade::Nu6_3
543 .activation_height(&self.network())
544 .is_some_and(|activation| *height >= activation);
545
546 match self.db.zs_prev_key_value_back_from(&ironwood_trees, height) {
548 Some((_first_duplicate_height, tree)) => Some(Arc::new(tree)),
549 None if !nu6_3_activated => Some(Default::default()),
550 None => panic!(
551 "Ironwood note commitment tree must exist for all heights at or below the finalized \
552 tip from NU6.3 activation onward"
553 ),
554 }
555 }
556
557 pub fn ironwood_tree_by_height_range<R>(
559 &self,
560 range: R,
561 ) -> impl Iterator<Item = (Height, Arc<orchard::tree::NoteCommitmentTree>)> + '_
562 where
563 R: std::ops::RangeBounds<Height>,
564 {
565 self.tree_by_height_range("ironwood_note_commitment_tree", range)
566 }
567
568 pub fn ironwood_subtree_list_by_index_range(
570 &self,
571 range: impl std::ops::RangeBounds<NoteCommitmentSubtreeIndex>,
572 ) -> BTreeMap<NoteCommitmentSubtreeIndex, NoteCommitmentSubtreeData<orchard::tree::Node>> {
573 self.subtree_list_by_index_range("ironwood_note_commitment_subtree", range)
574 }
575
576 fn ironwood_subtree_for_tip(&self) -> Option<NoteCommitmentSubtree<orchard::tree::Node>> {
578 self.subtree_for_tip("ironwood_note_commitment_subtree")
579 }
580
581 pub fn note_commitment_trees_for_tip(&self) -> NoteCommitmentTrees {
586 NoteCommitmentTrees {
587 sprout: self.sprout_tree_for_tip(),
588 sapling: self.sapling_tree_for_tip(),
589 sapling_subtree: self.sapling_subtree_for_tip(),
590 orchard: self.orchard_tree_for_tip(),
591 orchard_subtree: self.orchard_subtree_for_tip(),
592 ironwood: self.ironwood_tree_for_tip(),
593 ironwood_subtree: self.ironwood_subtree_for_tip(),
594 }
595 }
596}
597
598impl DiskWriteBatch {
599 pub fn prepare_shielded_transaction_batch(
605 &mut self,
606 zebra_db: &ZebraDb,
607 finalized: &FinalizedBlock,
608 ) {
609 #[cfg(feature = "indexer")]
610 let FinalizedBlock { block, height, .. } = finalized;
611
612 #[cfg(feature = "indexer")]
614 for (tx_index, transaction) in block.transactions.iter().enumerate() {
615 let tx_loc = TransactionLocation::from_usize(*height, tx_index);
616 self.prepare_nullifier_batch(zebra_db, transaction, tx_loc);
617 }
618
619 #[cfg(not(feature = "indexer"))]
620 for transaction in &finalized.block.transactions {
621 self.prepare_nullifier_batch(zebra_db, transaction);
622 }
623 }
624
625 #[allow(clippy::unwrap_in_result)]
632 pub fn prepare_nullifier_batch(
633 &mut self,
634 zebra_db: &ZebraDb,
635 transaction: &Transaction,
636 #[cfg(feature = "indexer")] transaction_location: TransactionLocation,
637 ) {
638 let db = &zebra_db.db;
639 let sprout_nullifiers = db.cf_handle("sprout_nullifiers").unwrap();
640 let sapling_nullifiers = db.cf_handle("sapling_nullifiers").unwrap();
641 let orchard_nullifiers = db.cf_handle("orchard_nullifiers").unwrap();
642 let ironwood_nullifiers = db.cf_handle("ironwood_nullifiers").unwrap();
643
644 #[cfg(feature = "indexer")]
645 let insert_value = transaction_location;
646 #[cfg(not(feature = "indexer"))]
647 let insert_value = ();
648
649 for sprout_nullifier in transaction.sprout_nullifiers() {
651 self.zs_insert(&sprout_nullifiers, sprout_nullifier, insert_value);
652 }
653 for sapling_nullifier in transaction.sapling_nullifiers() {
654 self.zs_insert(&sapling_nullifiers, sapling_nullifier, insert_value);
655 }
656 for orchard_nullifier in transaction.orchard_nullifiers() {
657 self.zs_insert(&orchard_nullifiers, orchard_nullifier, insert_value);
658 }
659 for ironwood_nullifier in transaction.ironwood_nullifiers() {
660 self.zs_insert(&ironwood_nullifiers, ironwood_nullifier, insert_value);
661 }
662 }
663
664 #[allow(clippy::unwrap_in_result)]
670 pub fn prepare_trees_batch(
671 &mut self,
672 zebra_db: &ZebraDb,
673 finalized: &FinalizedBlock,
674 prev_note_commitment_trees: Option<NoteCommitmentTrees>,
675 ) {
676 let FinalizedBlock {
677 height,
678 treestate:
679 Treestate {
680 note_commitment_trees,
681 history_tree,
682 },
683 ..
684 } = finalized;
685
686 let prev_sprout_tree = prev_note_commitment_trees.as_ref().map_or_else(
687 || zebra_db.sprout_tree_for_tip(),
688 |prev_trees| prev_trees.sprout.clone(),
689 );
690 let prev_sapling_tree = prev_note_commitment_trees.as_ref().map_or_else(
691 || zebra_db.sapling_tree_for_tip(),
692 |prev_trees| prev_trees.sapling.clone(),
693 );
694 let prev_orchard_tree = prev_note_commitment_trees.as_ref().map_or_else(
695 || zebra_db.orchard_tree_for_tip(),
696 |prev_trees| prev_trees.orchard.clone(),
697 );
698 let prev_ironwood_tree = prev_note_commitment_trees.as_ref().map_or_else(
699 || zebra_db.ironwood_tree_for_tip(),
700 |prev_trees| prev_trees.ironwood.clone(),
701 );
702
703 if height.is_min() || prev_sprout_tree != note_commitment_trees.sprout {
705 self.update_sprout_tree(zebra_db, ¬e_commitment_trees.sprout)
706 }
707
708 if height.is_min() || prev_sapling_tree != note_commitment_trees.sapling {
710 self.create_sapling_tree(zebra_db, height, ¬e_commitment_trees.sapling);
711
712 if let Some(subtree) = note_commitment_trees.sapling_subtree {
713 self.insert_sapling_subtree(zebra_db, &subtree);
714 }
715 }
716
717 if height.is_min() || prev_orchard_tree != note_commitment_trees.orchard {
719 self.create_orchard_tree(zebra_db, height, ¬e_commitment_trees.orchard);
720
721 if let Some(subtree) = note_commitment_trees.orchard_subtree {
722 self.insert_orchard_subtree(zebra_db, &subtree);
723 }
724 }
725
726 if height.is_min() || prev_ironwood_tree != note_commitment_trees.ironwood {
728 self.create_ironwood_tree(zebra_db, height, ¬e_commitment_trees.ironwood);
729
730 if let Some(subtree) = note_commitment_trees.ironwood_subtree {
731 self.insert_ironwood_subtree(zebra_db, &subtree);
732 }
733 }
734
735 self.update_history_tree(zebra_db, history_tree);
736 }
737
738 pub fn update_sprout_tree(
742 &mut self,
743 zebra_db: &ZebraDb,
744 tree: &sprout::tree::NoteCommitmentTree,
745 ) {
746 let sprout_anchors = zebra_db.db.cf_handle("sprout_anchors").unwrap();
747 let sprout_tree_cf = zebra_db
748 .db
749 .cf_handle("sprout_note_commitment_tree")
750 .unwrap();
751
752 self.zs_insert(&sprout_anchors, tree.root(), tree);
755 self.zs_insert(&sprout_tree_cf, (), tree);
756 }
757
758 pub fn delete_range_sprout_tree(&mut self, zebra_db: &ZebraDb, from: &Height, to: &Height) {
764 let sprout_tree_cf = zebra_db
765 .db
766 .cf_handle("sprout_note_commitment_tree")
767 .unwrap();
768
769 self.zs_delete_range(&sprout_tree_cf, from, to);
771 }
772
773 #[allow(dead_code)]
775 pub fn delete_sprout_anchor(&mut self, zebra_db: &ZebraDb, anchor: &sprout::tree::Root) {
776 let sprout_anchors = zebra_db.db.cf_handle("sprout_anchors").unwrap();
777 self.zs_delete(&sprout_anchors, anchor);
778 }
779
780 pub fn create_sapling_tree(
785 &mut self,
786 zebra_db: &ZebraDb,
787 height: &Height,
788 tree: &sapling::tree::NoteCommitmentTree,
789 ) {
790 let sapling_anchors = zebra_db.db.cf_handle("sapling_anchors").unwrap();
791 let sapling_tree_cf = zebra_db
792 .db
793 .cf_handle("sapling_note_commitment_tree")
794 .unwrap();
795
796 self.zs_insert(&sapling_anchors, tree.root(), ());
797 self.zs_insert(&sapling_tree_cf, height, tree);
798 }
799
800 pub fn insert_sapling_subtree(
802 &mut self,
803 zebra_db: &ZebraDb,
804 subtree: &NoteCommitmentSubtree<sapling_crypto::Node>,
805 ) {
806 let sapling_subtree_cf = zebra_db
807 .db
808 .cf_handle("sapling_note_commitment_subtree")
809 .unwrap();
810 self.zs_insert(&sapling_subtree_cf, subtree.index, subtree.into_data());
811 }
812
813 pub fn delete_sapling_tree(&mut self, zebra_db: &ZebraDb, height: &Height) {
815 let sapling_tree_cf = zebra_db
816 .db
817 .cf_handle("sapling_note_commitment_tree")
818 .unwrap();
819 self.zs_delete(&sapling_tree_cf, height);
820 }
821
822 #[allow(dead_code)]
825 pub fn delete_range_sapling_tree(&mut self, zebra_db: &ZebraDb, from: &Height, to: &Height) {
826 let sapling_tree_cf = zebra_db
827 .db
828 .cf_handle("sapling_note_commitment_tree")
829 .unwrap();
830
831 self.zs_delete_range(&sapling_tree_cf, from, to);
833 }
834
835 #[allow(dead_code)]
837 pub fn delete_sapling_anchor(&mut self, zebra_db: &ZebraDb, anchor: &sapling::tree::Root) {
838 let sapling_anchors = zebra_db.db.cf_handle("sapling_anchors").unwrap();
839 self.zs_delete(&sapling_anchors, anchor);
840 }
841
842 pub fn delete_range_sapling_subtree(
845 &mut self,
846 zebra_db: &ZebraDb,
847 from: NoteCommitmentSubtreeIndex,
848 to: NoteCommitmentSubtreeIndex,
849 ) {
850 let sapling_subtree_cf = zebra_db
851 .db
852 .cf_handle("sapling_note_commitment_subtree")
853 .unwrap();
854
855 self.zs_delete_range(&sapling_subtree_cf, from, to);
857 }
858
859 pub fn create_orchard_tree(
864 &mut self,
865 zebra_db: &ZebraDb,
866 height: &Height,
867 tree: &orchard::tree::NoteCommitmentTree,
868 ) {
869 self.create_note_commitment_tree(
870 zebra_db,
871 "orchard_anchors",
872 "orchard_note_commitment_tree",
873 height,
874 tree,
875 );
876 }
877
878 pub fn insert_orchard_subtree(
880 &mut self,
881 zebra_db: &ZebraDb,
882 subtree: &NoteCommitmentSubtree<orchard::tree::Node>,
883 ) {
884 self.insert_note_commitment_subtree(zebra_db, "orchard_note_commitment_subtree", subtree);
885 }
886
887 pub fn create_ironwood_tree(
892 &mut self,
893 zebra_db: &ZebraDb,
894 height: &Height,
895 tree: &orchard::tree::NoteCommitmentTree,
896 ) {
897 self.create_note_commitment_tree(
898 zebra_db,
899 "ironwood_anchors",
900 "ironwood_note_commitment_tree",
901 height,
902 tree,
903 );
904 }
905
906 pub fn insert_ironwood_subtree(
908 &mut self,
909 zebra_db: &ZebraDb,
910 subtree: &NoteCommitmentSubtree<orchard::tree::Node>,
911 ) {
912 self.insert_note_commitment_subtree(zebra_db, "ironwood_note_commitment_subtree", subtree);
913 }
914
915 fn create_note_commitment_tree(
920 &mut self,
921 zebra_db: &ZebraDb,
922 anchors_cf: &str,
923 tree_cf: &str,
924 height: &Height,
925 tree: &orchard::tree::NoteCommitmentTree,
926 ) {
927 let anchors = zebra_db.db.cf_handle(anchors_cf).unwrap();
928 let tree_cf = zebra_db.db.cf_handle(tree_cf).unwrap();
929
930 self.zs_insert(&anchors, tree.root(), ());
931 self.zs_insert(&tree_cf, height, tree);
932 }
933
934 fn insert_note_commitment_subtree(
936 &mut self,
937 zebra_db: &ZebraDb,
938 subtree_cf: &str,
939 subtree: &NoteCommitmentSubtree<orchard::tree::Node>,
940 ) {
941 let subtree_cf = zebra_db.db.cf_handle(subtree_cf).unwrap();
942 self.zs_insert(&subtree_cf, subtree.index, subtree.into_data());
943 }
944
945 pub fn delete_orchard_tree(&mut self, zebra_db: &ZebraDb, height: &Height) {
947 let orchard_tree_cf = zebra_db
948 .db
949 .cf_handle("orchard_note_commitment_tree")
950 .unwrap();
951 self.zs_delete(&orchard_tree_cf, height);
952 }
953
954 #[allow(dead_code)]
957 pub fn delete_range_orchard_tree(&mut self, zebra_db: &ZebraDb, from: &Height, to: &Height) {
958 let orchard_tree_cf = zebra_db
959 .db
960 .cf_handle("orchard_note_commitment_tree")
961 .unwrap();
962
963 self.zs_delete_range(&orchard_tree_cf, from, to);
965 }
966
967 #[allow(dead_code)]
969 pub fn delete_orchard_anchor(&mut self, zebra_db: &ZebraDb, anchor: &orchard::tree::Root) {
970 let orchard_anchors = zebra_db.db.cf_handle("orchard_anchors").unwrap();
971 self.zs_delete(&orchard_anchors, anchor);
972 }
973
974 pub fn delete_range_orchard_subtree(
977 &mut self,
978 zebra_db: &ZebraDb,
979 from: NoteCommitmentSubtreeIndex,
980 to: NoteCommitmentSubtreeIndex,
981 ) {
982 let orchard_subtree_cf = zebra_db
983 .db
984 .cf_handle("orchard_note_commitment_subtree")
985 .unwrap();
986
987 self.zs_delete_range(&orchard_subtree_cf, from, to);
989 }
990}