change(state): Wrap commitment trees into `Arc` (#4757)
* Wrap Sprout note commitment trees into `Arc` * Remove a redundant comment * Rephrase a comment about chain forking * Remove a redundant comment The comment is not valid because Zebra uses `bridgetree::Frontier`s from the `incrementalmerkletree` crate to represent its note commitment trees. This `struct` does not support popping elements from the tree. * Wrap Sapling commitment trees into `Arc` * Remove unnecessary `as_ref`s * Wrap Orchard commitment trees into `Arc`
This commit is contained in:
parent
61eeeb0b66
commit
485bac819d
|
|
@ -1,7 +1,7 @@
|
||||||
//! Checks for whether cited anchors are previously-computed note commitment
|
//! Checks for whether cited anchors are previously-computed note commitment
|
||||||
//! tree roots.
|
//! tree roots.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
use zebra_chain::sprout;
|
use zebra_chain::sprout;
|
||||||
|
|
||||||
|
|
@ -29,7 +29,7 @@ pub(crate) fn anchors_refer_to_earlier_treestates(
|
||||||
if transaction.has_sprout_joinsplit_data() {
|
if transaction.has_sprout_joinsplit_data() {
|
||||||
let mut interstitial_trees: HashMap<
|
let mut interstitial_trees: HashMap<
|
||||||
sprout::tree::Root,
|
sprout::tree::Root,
|
||||||
sprout::tree::NoteCommitmentTree,
|
Arc<sprout::tree::NoteCommitmentTree>,
|
||||||
> = HashMap::new();
|
> = HashMap::new();
|
||||||
|
|
||||||
for joinsplit in transaction.sprout_groth16_joinsplits() {
|
for joinsplit in transaction.sprout_groth16_joinsplits() {
|
||||||
|
|
@ -90,11 +90,13 @@ pub(crate) fn anchors_refer_to_earlier_treestates(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let input_tree_inner = Arc::make_mut(&mut input_tree);
|
||||||
|
|
||||||
tracing::debug!(?joinsplit.anchor, "validated sprout anchor");
|
tracing::debug!(?joinsplit.anchor, "validated sprout anchor");
|
||||||
|
|
||||||
// Add new anchors to the interstitial note commitment tree.
|
// Add new anchors to the interstitial note commitment tree.
|
||||||
for cm in joinsplit.commitments {
|
for cm in joinsplit.commitments {
|
||||||
input_tree
|
input_tree_inner
|
||||||
.append(cm)
|
.append(cm)
|
||||||
.expect("note commitment should be appendable to the tree");
|
.expect("note commitment should be appendable to the tree");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -219,8 +219,8 @@ fn snapshot_block_and_transaction_data(state: &FinalizedState) {
|
||||||
.orchard_note_commitment_tree_by_height(&block::Height::MIN)
|
.orchard_note_commitment_tree_by_height(&block::Height::MIN)
|
||||||
.expect("the genesis block in the database has an Orchard tree");
|
.expect("the genesis block in the database has an Orchard tree");
|
||||||
|
|
||||||
assert_eq!(sapling_tree, sapling::tree::NoteCommitmentTree::default());
|
assert_eq!(*sapling_tree, sapling::tree::NoteCommitmentTree::default());
|
||||||
assert_eq!(orchard_tree, orchard::tree::NoteCommitmentTree::default());
|
assert_eq!(*orchard_tree, orchard::tree::NoteCommitmentTree::default());
|
||||||
|
|
||||||
// Blocks
|
// Blocks
|
||||||
let mut stored_block_hashes = Vec::new();
|
let mut stored_block_hashes = Vec::new();
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@
|
||||||
//! The [`crate::constants::DATABASE_FORMAT_VERSION`] constant must
|
//! The [`crate::constants::DATABASE_FORMAT_VERSION`] constant must
|
||||||
//! be incremented each time the database format (column, serialization, etc) changes.
|
//! be incremented each time the database format (column, serialization, etc) changes.
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use zebra_chain::{
|
use zebra_chain::{
|
||||||
block::Height, history_tree::HistoryTree, orchard, sapling, sprout, transaction::Transaction,
|
block::Height, history_tree::HistoryTree, orchard, sapling, sprout, transaction::Transaction,
|
||||||
};
|
};
|
||||||
|
|
@ -28,9 +30,9 @@ use crate::{
|
||||||
/// An argument wrapper struct for note commitment trees.
|
/// An argument wrapper struct for note commitment trees.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct NoteCommitmentTrees {
|
pub struct NoteCommitmentTrees {
|
||||||
sprout: sprout::tree::NoteCommitmentTree,
|
sprout: Arc<sprout::tree::NoteCommitmentTree>,
|
||||||
sapling: sapling::tree::NoteCommitmentTree,
|
sapling: Arc<sapling::tree::NoteCommitmentTree>,
|
||||||
orchard: orchard::tree::NoteCommitmentTree,
|
orchard: Arc<orchard::tree::NoteCommitmentTree>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ZebraDb {
|
impl ZebraDb {
|
||||||
|
|
@ -75,16 +77,17 @@ impl ZebraDb {
|
||||||
|
|
||||||
/// Returns the Sprout note commitment tree of the finalized tip
|
/// Returns the Sprout note commitment tree of the finalized tip
|
||||||
/// or the empty tree if the state is empty.
|
/// or the empty tree if the state is empty.
|
||||||
pub fn sprout_note_commitment_tree(&self) -> sprout::tree::NoteCommitmentTree {
|
pub fn sprout_note_commitment_tree(&self) -> Arc<sprout::tree::NoteCommitmentTree> {
|
||||||
let height = match self.finalized_tip_height() {
|
let height = match self.finalized_tip_height() {
|
||||||
Some(h) => h,
|
Some(h) => h,
|
||||||
None => return Default::default(),
|
None => return Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let sprout_note_commitment_tree = self.db.cf_handle("sprout_note_commitment_tree").unwrap();
|
let sprout_nct_handle = self.db.cf_handle("sprout_note_commitment_tree").unwrap();
|
||||||
|
|
||||||
self.db
|
self.db
|
||||||
.zs_get(&sprout_note_commitment_tree, &height)
|
.zs_get(&sprout_nct_handle, &height)
|
||||||
|
.map(Arc::new)
|
||||||
.expect("Sprout note commitment tree must exist if there is a finalized tip")
|
.expect("Sprout note commitment tree must exist if there is a finalized tip")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,25 +98,27 @@ impl ZebraDb {
|
||||||
pub fn sprout_note_commitment_tree_by_anchor(
|
pub fn sprout_note_commitment_tree_by_anchor(
|
||||||
&self,
|
&self,
|
||||||
sprout_anchor: &sprout::tree::Root,
|
sprout_anchor: &sprout::tree::Root,
|
||||||
) -> Option<sprout::tree::NoteCommitmentTree> {
|
) -> Option<Arc<sprout::tree::NoteCommitmentTree>> {
|
||||||
let sprout_anchors = self.db.cf_handle("sprout_anchors").unwrap();
|
let sprout_anchors_handle = self.db.cf_handle("sprout_anchors").unwrap();
|
||||||
|
|
||||||
self.db.zs_get(&sprout_anchors, sprout_anchor)
|
self.db
|
||||||
|
.zs_get(&sprout_anchors_handle, sprout_anchor)
|
||||||
|
.map(Arc::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the Sapling note commitment tree of the finalized tip
|
/// Returns the Sapling note commitment tree of the finalized tip
|
||||||
/// or the empty tree if the state is empty.
|
/// or the empty tree if the state is empty.
|
||||||
pub fn sapling_note_commitment_tree(&self) -> sapling::tree::NoteCommitmentTree {
|
pub fn sapling_note_commitment_tree(&self) -> Arc<sapling::tree::NoteCommitmentTree> {
|
||||||
let height = match self.finalized_tip_height() {
|
let height = match self.finalized_tip_height() {
|
||||||
Some(h) => h,
|
Some(h) => h,
|
||||||
None => return Default::default(),
|
None => return Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let sapling_note_commitment_tree =
|
let sapling_nct_handle = self.db.cf_handle("sapling_note_commitment_tree").unwrap();
|
||||||
self.db.cf_handle("sapling_note_commitment_tree").unwrap();
|
|
||||||
|
|
||||||
self.db
|
self.db
|
||||||
.zs_get(&sapling_note_commitment_tree, &height)
|
.zs_get(&sapling_nct_handle, &height)
|
||||||
|
.map(Arc::new)
|
||||||
.expect("Sapling note commitment tree must exist if there is a finalized tip")
|
.expect("Sapling note commitment tree must exist if there is a finalized tip")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,25 +128,25 @@ impl ZebraDb {
|
||||||
pub fn sapling_note_commitment_tree_by_height(
|
pub fn sapling_note_commitment_tree_by_height(
|
||||||
&self,
|
&self,
|
||||||
height: &Height,
|
height: &Height,
|
||||||
) -> Option<sapling::tree::NoteCommitmentTree> {
|
) -> Option<Arc<sapling::tree::NoteCommitmentTree>> {
|
||||||
let sapling_trees = self.db.cf_handle("sapling_note_commitment_tree").unwrap();
|
let sapling_trees = self.db.cf_handle("sapling_note_commitment_tree").unwrap();
|
||||||
|
|
||||||
self.db.zs_get(&sapling_trees, height)
|
self.db.zs_get(&sapling_trees, height).map(Arc::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the Orchard note commitment tree of the finalized tip
|
/// Returns the Orchard note commitment tree of the finalized tip
|
||||||
/// or the empty tree if the state is empty.
|
/// or the empty tree if the state is empty.
|
||||||
pub fn orchard_note_commitment_tree(&self) -> orchard::tree::NoteCommitmentTree {
|
pub fn orchard_note_commitment_tree(&self) -> Arc<orchard::tree::NoteCommitmentTree> {
|
||||||
let height = match self.finalized_tip_height() {
|
let height = match self.finalized_tip_height() {
|
||||||
Some(h) => h,
|
Some(h) => h,
|
||||||
None => return Default::default(),
|
None => return Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let orchard_note_commitment_tree =
|
let orchard_nct_handle = self.db.cf_handle("orchard_note_commitment_tree").unwrap();
|
||||||
self.db.cf_handle("orchard_note_commitment_tree").unwrap();
|
|
||||||
|
|
||||||
self.db
|
self.db
|
||||||
.zs_get(&orchard_note_commitment_tree, &height)
|
.zs_get(&orchard_nct_handle, &height)
|
||||||
|
.map(Arc::new)
|
||||||
.expect("Orchard note commitment tree must exist if there is a finalized tip")
|
.expect("Orchard note commitment tree must exist if there is a finalized tip")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,10 +156,10 @@ impl ZebraDb {
|
||||||
pub fn orchard_note_commitment_tree_by_height(
|
pub fn orchard_note_commitment_tree_by_height(
|
||||||
&self,
|
&self,
|
||||||
height: &Height,
|
height: &Height,
|
||||||
) -> Option<orchard::tree::NoteCommitmentTree> {
|
) -> Option<Arc<orchard::tree::NoteCommitmentTree>> {
|
||||||
let orchard_trees = self.db.cf_handle("orchard_note_commitment_tree").unwrap();
|
let orchard_trees = self.db.cf_handle("orchard_note_commitment_tree").unwrap();
|
||||||
|
|
||||||
self.db.zs_get(&orchard_trees, height)
|
self.db.zs_get(&orchard_trees, height).map(Arc::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the shielded note commitment trees of the finalized tip
|
/// Returns the shielded note commitment trees of the finalized tip
|
||||||
|
|
@ -238,21 +243,19 @@ impl DiskWriteBatch {
|
||||||
transaction: &Transaction,
|
transaction: &Transaction,
|
||||||
note_commitment_trees: &mut NoteCommitmentTrees,
|
note_commitment_trees: &mut NoteCommitmentTrees,
|
||||||
) -> Result<(), BoxError> {
|
) -> Result<(), BoxError> {
|
||||||
// Update the note commitment trees
|
let sprout_nct = Arc::make_mut(&mut note_commitment_trees.sprout);
|
||||||
for sprout_note_commitment in transaction.sprout_note_commitments() {
|
for sprout_note_commitment in transaction.sprout_note_commitments() {
|
||||||
note_commitment_trees
|
sprout_nct.append(*sprout_note_commitment)?;
|
||||||
.sprout
|
|
||||||
.append(*sprout_note_commitment)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let sapling_nct = Arc::make_mut(&mut note_commitment_trees.sapling);
|
||||||
for sapling_note_commitment in transaction.sapling_note_commitments() {
|
for sapling_note_commitment in transaction.sapling_note_commitments() {
|
||||||
note_commitment_trees
|
sapling_nct.append(*sapling_note_commitment)?;
|
||||||
.sapling
|
|
||||||
.append(*sapling_note_commitment)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let orchard_nct = Arc::make_mut(&mut note_commitment_trees.orchard);
|
||||||
for orchard_note_commitment in transaction.orchard_note_commitments() {
|
for orchard_note_commitment in transaction.orchard_note_commitments() {
|
||||||
note_commitment_trees
|
orchard_nct.append(*orchard_note_commitment)?;
|
||||||
.orchard
|
|
||||||
.append(*orchard_note_commitment)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -385,9 +385,9 @@ impl NonFinalizedState {
|
||||||
fn parent_chain(
|
fn parent_chain(
|
||||||
&mut self,
|
&mut self,
|
||||||
parent_hash: block::Hash,
|
parent_hash: block::Hash,
|
||||||
sprout_note_commitment_tree: sprout::tree::NoteCommitmentTree,
|
sprout_note_commitment_tree: Arc<sprout::tree::NoteCommitmentTree>,
|
||||||
sapling_note_commitment_tree: sapling::tree::NoteCommitmentTree,
|
sapling_note_commitment_tree: Arc<sapling::tree::NoteCommitmentTree>,
|
||||||
orchard_note_commitment_tree: orchard::tree::NoteCommitmentTree,
|
orchard_note_commitment_tree: Arc<orchard::tree::NoteCommitmentTree>,
|
||||||
history_tree: HistoryTree,
|
history_tree: HistoryTree,
|
||||||
) -> Result<Arc<Chain>, ValidateContextError> {
|
) -> Result<Arc<Chain>, ValidateContextError> {
|
||||||
match self.find_chain(|chain| chain.non_finalized_tip_hash() == parent_hash) {
|
match self.find_chain(|chain| chain.non_finalized_tip_hash() == parent_hash) {
|
||||||
|
|
|
||||||
|
|
@ -63,21 +63,23 @@ pub struct Chain {
|
||||||
|
|
||||||
/// The Sprout note commitment tree of the tip of this [`Chain`],
|
/// The Sprout note commitment tree of the tip of this [`Chain`],
|
||||||
/// including all finalized notes, and the non-finalized notes in this chain.
|
/// including all finalized notes, and the non-finalized notes in this chain.
|
||||||
pub(super) sprout_note_commitment_tree: sprout::tree::NoteCommitmentTree,
|
pub(super) sprout_note_commitment_tree: Arc<sprout::tree::NoteCommitmentTree>,
|
||||||
/// The Sprout note commitment tree for each anchor.
|
/// The Sprout note commitment tree for each anchor.
|
||||||
/// This is required for interstitial states.
|
/// This is required for interstitial states.
|
||||||
pub(crate) sprout_trees_by_anchor:
|
pub(crate) sprout_trees_by_anchor:
|
||||||
HashMap<sprout::tree::Root, sprout::tree::NoteCommitmentTree>,
|
HashMap<sprout::tree::Root, Arc<sprout::tree::NoteCommitmentTree>>,
|
||||||
/// The Sapling note commitment tree of the tip of this [`Chain`],
|
/// The Sapling note commitment tree of the tip of this [`Chain`],
|
||||||
/// including all finalized notes, and the non-finalized notes in this chain.
|
/// including all finalized notes, and the non-finalized notes in this chain.
|
||||||
pub(super) sapling_note_commitment_tree: sapling::tree::NoteCommitmentTree,
|
pub(super) sapling_note_commitment_tree: Arc<sapling::tree::NoteCommitmentTree>,
|
||||||
/// The Sapling note commitment tree for each height.
|
/// The Sapling note commitment tree for each height.
|
||||||
pub(crate) sapling_trees_by_height: BTreeMap<block::Height, sapling::tree::NoteCommitmentTree>,
|
pub(crate) sapling_trees_by_height:
|
||||||
|
BTreeMap<block::Height, Arc<sapling::tree::NoteCommitmentTree>>,
|
||||||
/// The Orchard note commitment tree of the tip of this [`Chain`],
|
/// The Orchard note commitment tree of the tip of this [`Chain`],
|
||||||
/// including all finalized notes, and the non-finalized notes in this chain.
|
/// including all finalized notes, and the non-finalized notes in this chain.
|
||||||
pub(super) orchard_note_commitment_tree: orchard::tree::NoteCommitmentTree,
|
pub(super) orchard_note_commitment_tree: Arc<orchard::tree::NoteCommitmentTree>,
|
||||||
/// The Orchard note commitment tree for each height.
|
/// The Orchard note commitment tree for each height.
|
||||||
pub(crate) orchard_trees_by_height: BTreeMap<block::Height, orchard::tree::NoteCommitmentTree>,
|
pub(crate) orchard_trees_by_height:
|
||||||
|
BTreeMap<block::Height, Arc<orchard::tree::NoteCommitmentTree>>,
|
||||||
/// The ZIP-221 history tree of the tip of this [`Chain`],
|
/// The ZIP-221 history tree of the tip of this [`Chain`],
|
||||||
/// including all finalized blocks, and the non-finalized `blocks` in this chain.
|
/// including all finalized blocks, and the non-finalized `blocks` in this chain.
|
||||||
pub(crate) history_tree: HistoryTree,
|
pub(crate) history_tree: HistoryTree,
|
||||||
|
|
@ -125,9 +127,9 @@ impl Chain {
|
||||||
/// Create a new Chain with the given trees and network.
|
/// Create a new Chain with the given trees and network.
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
network: Network,
|
network: Network,
|
||||||
sprout_note_commitment_tree: sprout::tree::NoteCommitmentTree,
|
sprout_note_commitment_tree: Arc<sprout::tree::NoteCommitmentTree>,
|
||||||
sapling_note_commitment_tree: sapling::tree::NoteCommitmentTree,
|
sapling_note_commitment_tree: Arc<sapling::tree::NoteCommitmentTree>,
|
||||||
orchard_note_commitment_tree: orchard::tree::NoteCommitmentTree,
|
orchard_note_commitment_tree: Arc<orchard::tree::NoteCommitmentTree>,
|
||||||
history_tree: HistoryTree,
|
history_tree: HistoryTree,
|
||||||
finalized_tip_chain_value_pools: ValueBalance<NonNegative>,
|
finalized_tip_chain_value_pools: ValueBalance<NonNegative>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
|
@ -264,15 +266,16 @@ impl Chain {
|
||||||
/// Fork a chain at the block with the given hash, if it is part of this
|
/// Fork a chain at the block with the given hash, if it is part of this
|
||||||
/// chain.
|
/// chain.
|
||||||
///
|
///
|
||||||
/// The trees must match the trees of the finalized tip and are used
|
/// The passed trees must match the trees of the finalized tip. They are
|
||||||
/// to rebuild them after the fork.
|
/// extended by the commitments from the newly forked chain up to the passed
|
||||||
|
/// `fork_tip`.
|
||||||
#[allow(clippy::unwrap_in_result)]
|
#[allow(clippy::unwrap_in_result)]
|
||||||
pub fn fork(
|
pub fn fork(
|
||||||
&self,
|
&self,
|
||||||
fork_tip: block::Hash,
|
fork_tip: block::Hash,
|
||||||
sprout_note_commitment_tree: sprout::tree::NoteCommitmentTree,
|
sprout_note_commitment_tree: Arc<sprout::tree::NoteCommitmentTree>,
|
||||||
sapling_note_commitment_tree: sapling::tree::NoteCommitmentTree,
|
sapling_note_commitment_tree: Arc<sapling::tree::NoteCommitmentTree>,
|
||||||
orchard_note_commitment_tree: orchard::tree::NoteCommitmentTree,
|
orchard_note_commitment_tree: Arc<orchard::tree::NoteCommitmentTree>,
|
||||||
history_tree: HistoryTree,
|
history_tree: HistoryTree,
|
||||||
) -> Result<Option<Self>, ValidateContextError> {
|
) -> Result<Option<Self>, ValidateContextError> {
|
||||||
if !self.height_by_hash.contains_key(&fork_tip) {
|
if !self.height_by_hash.contains_key(&fork_tip) {
|
||||||
|
|
@ -290,29 +293,27 @@ impl Chain {
|
||||||
forked.pop_tip();
|
forked.pop_tip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let sprout_nct = Arc::make_mut(&mut forked.sprout_note_commitment_tree);
|
||||||
|
let sapling_nct = Arc::make_mut(&mut forked.sapling_note_commitment_tree);
|
||||||
|
let orchard_nct = Arc::make_mut(&mut forked.orchard_note_commitment_tree);
|
||||||
|
|
||||||
// Rebuild the note commitment trees, starting from the finalized tip tree.
|
// Rebuild the note commitment trees, starting from the finalized tip tree.
|
||||||
// TODO: change to a more efficient approach by removing nodes
|
|
||||||
// from the tree of the original chain (in [`Self::pop_tip`]).
|
|
||||||
// See https://github.com/ZcashFoundation/zebra/issues/2378
|
|
||||||
for block in forked.blocks.values() {
|
for block in forked.blocks.values() {
|
||||||
for transaction in block.block.transactions.iter() {
|
for transaction in block.block.transactions.iter() {
|
||||||
for sprout_note_commitment in transaction.sprout_note_commitments() {
|
for sprout_note_commitment in transaction.sprout_note_commitments() {
|
||||||
forked
|
sprout_nct
|
||||||
.sprout_note_commitment_tree
|
|
||||||
.append(*sprout_note_commitment)
|
.append(*sprout_note_commitment)
|
||||||
.expect("must work since it was already appended before the fork");
|
.expect("must work since it was already appended before the fork");
|
||||||
}
|
}
|
||||||
|
|
||||||
for sapling_note_commitment in transaction.sapling_note_commitments() {
|
for sapling_note_commitment in transaction.sapling_note_commitments() {
|
||||||
forked
|
sapling_nct
|
||||||
.sapling_note_commitment_tree
|
|
||||||
.append(*sapling_note_commitment)
|
.append(*sapling_note_commitment)
|
||||||
.expect("must work since it was already appended before the fork");
|
.expect("must work since it was already appended before the fork");
|
||||||
}
|
}
|
||||||
|
|
||||||
for orchard_note_commitment in transaction.orchard_note_commitments() {
|
for orchard_note_commitment in transaction.orchard_note_commitments() {
|
||||||
forked
|
orchard_nct
|
||||||
.orchard_note_commitment_tree
|
|
||||||
.append(*orchard_note_commitment)
|
.append(*orchard_note_commitment)
|
||||||
.expect("must work since it was already appended before the fork");
|
.expect("must work since it was already appended before the fork");
|
||||||
}
|
}
|
||||||
|
|
@ -401,11 +402,11 @@ impl Chain {
|
||||||
pub fn sapling_tree(
|
pub fn sapling_tree(
|
||||||
&self,
|
&self,
|
||||||
hash_or_height: HashOrHeight,
|
hash_or_height: HashOrHeight,
|
||||||
) -> Option<&sapling::tree::NoteCommitmentTree> {
|
) -> Option<Arc<sapling::tree::NoteCommitmentTree>> {
|
||||||
let height =
|
let height =
|
||||||
hash_or_height.height_or_else(|hash| self.height_by_hash.get(&hash).cloned())?;
|
hash_or_height.height_or_else(|hash| self.height_by_hash.get(&hash).cloned())?;
|
||||||
|
|
||||||
self.sapling_trees_by_height.get(&height)
|
self.sapling_trees_by_height.get(&height).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the Orchard
|
/// Returns the Orchard
|
||||||
|
|
@ -414,11 +415,11 @@ impl Chain {
|
||||||
pub fn orchard_tree(
|
pub fn orchard_tree(
|
||||||
&self,
|
&self,
|
||||||
hash_or_height: HashOrHeight,
|
hash_or_height: HashOrHeight,
|
||||||
) -> Option<&orchard::tree::NoteCommitmentTree> {
|
) -> Option<Arc<orchard::tree::NoteCommitmentTree>> {
|
||||||
let height =
|
let height =
|
||||||
hash_or_height.height_or_else(|hash| self.height_by_hash.get(&hash).cloned())?;
|
hash_or_height.height_or_else(|hash| self.height_by_hash.get(&hash).cloned())?;
|
||||||
|
|
||||||
self.orchard_trees_by_height.get(&height)
|
self.orchard_trees_by_height.get(&height).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the block hash of the tip block.
|
/// Returns the block hash of the tip block.
|
||||||
|
|
@ -639,9 +640,9 @@ impl Chain {
|
||||||
/// Useful when forking, where the trees are rebuilt anyway.
|
/// Useful when forking, where the trees are rebuilt anyway.
|
||||||
fn with_trees(
|
fn with_trees(
|
||||||
&self,
|
&self,
|
||||||
sprout_note_commitment_tree: sprout::tree::NoteCommitmentTree,
|
sprout_note_commitment_tree: Arc<sprout::tree::NoteCommitmentTree>,
|
||||||
sapling_note_commitment_tree: sapling::tree::NoteCommitmentTree,
|
sapling_note_commitment_tree: Arc<sapling::tree::NoteCommitmentTree>,
|
||||||
orchard_note_commitment_tree: orchard::tree::NoteCommitmentTree,
|
orchard_note_commitment_tree: Arc<orchard::tree::NoteCommitmentTree>,
|
||||||
history_tree: HistoryTree,
|
history_tree: HistoryTree,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Chain {
|
Chain {
|
||||||
|
|
@ -1203,8 +1204,10 @@ impl UpdateWith<Option<transaction::JoinSplitData<Groth16Proof>>> for Chain {
|
||||||
joinsplit_data: &Option<transaction::JoinSplitData<Groth16Proof>>,
|
joinsplit_data: &Option<transaction::JoinSplitData<Groth16Proof>>,
|
||||||
) -> Result<(), ValidateContextError> {
|
) -> Result<(), ValidateContextError> {
|
||||||
if let Some(joinsplit_data) = joinsplit_data {
|
if let Some(joinsplit_data) = joinsplit_data {
|
||||||
|
let sprout_ncm = Arc::make_mut(&mut self.sprout_note_commitment_tree);
|
||||||
|
|
||||||
for cm in joinsplit_data.note_commitments() {
|
for cm in joinsplit_data.note_commitments() {
|
||||||
self.sprout_note_commitment_tree.append(*cm)?;
|
sprout_ncm.append(*cm)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
check::nullifier::add_to_non_finalized_chain_unique(
|
check::nullifier::add_to_non_finalized_chain_unique(
|
||||||
|
|
@ -1245,11 +1248,13 @@ where
|
||||||
sapling_shielded_data: &Option<sapling::ShieldedData<AnchorV>>,
|
sapling_shielded_data: &Option<sapling::ShieldedData<AnchorV>>,
|
||||||
) -> Result<(), ValidateContextError> {
|
) -> Result<(), ValidateContextError> {
|
||||||
if let Some(sapling_shielded_data) = sapling_shielded_data {
|
if let Some(sapling_shielded_data) = sapling_shielded_data {
|
||||||
|
let sapling_nct = Arc::make_mut(&mut self.sapling_note_commitment_tree);
|
||||||
|
|
||||||
// The `_u` here indicates that the Sapling note commitment is
|
// The `_u` here indicates that the Sapling note commitment is
|
||||||
// specified only by the `u`-coordinate of the Jubjub curve
|
// specified only by the `u`-coordinate of the Jubjub curve
|
||||||
// point `(u, v)`.
|
// point `(u, v)`.
|
||||||
for cm_u in sapling_shielded_data.note_commitments() {
|
for cm_u in sapling_shielded_data.note_commitments() {
|
||||||
self.sapling_note_commitment_tree.append(*cm_u)?;
|
sapling_nct.append(*cm_u)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
check::nullifier::add_to_non_finalized_chain_unique(
|
check::nullifier::add_to_non_finalized_chain_unique(
|
||||||
|
|
@ -1291,8 +1296,10 @@ impl UpdateWith<Option<orchard::ShieldedData>> for Chain {
|
||||||
orchard_shielded_data: &Option<orchard::ShieldedData>,
|
orchard_shielded_data: &Option<orchard::ShieldedData>,
|
||||||
) -> Result<(), ValidateContextError> {
|
) -> Result<(), ValidateContextError> {
|
||||||
if let Some(orchard_shielded_data) = orchard_shielded_data {
|
if let Some(orchard_shielded_data) = orchard_shielded_data {
|
||||||
|
let orchard_nct = Arc::make_mut(&mut self.orchard_note_commitment_tree);
|
||||||
|
|
||||||
for cm_x in orchard_shielded_data.note_commitments() {
|
for cm_x in orchard_shielded_data.note_commitments() {
|
||||||
self.orchard_note_commitment_tree.append(*cm_x)?;
|
orchard_nct.append(*cm_x)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
check::nullifier::add_to_non_finalized_chain_unique(
|
check::nullifier::add_to_non_finalized_chain_unique(
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,6 @@ where
|
||||||
// we check the most efficient alternative first. (`chain` is always in
|
// we check the most efficient alternative first. (`chain` is always in
|
||||||
// memory, but `db` stores transactions on disk, with a memory cache.)
|
// memory, but `db` stores transactions on disk, with a memory cache.)
|
||||||
chain
|
chain
|
||||||
.as_ref()
|
|
||||||
.and_then(|chain| {
|
.and_then(|chain| {
|
||||||
chain
|
chain
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|
@ -128,9 +127,7 @@ where
|
||||||
// state, we check the most efficient alternative first. (`chain` is always
|
// state, we check the most efficient alternative first. (`chain` is always
|
||||||
// in memory, but `db` stores blocks on disk, with a memory cache.)
|
// in memory, but `db` stores blocks on disk, with a memory cache.)
|
||||||
chain
|
chain
|
||||||
.as_ref()
|
.and_then(|chain| chain.as_ref().sapling_tree(hash_or_height))
|
||||||
.and_then(|chain| chain.as_ref().sapling_tree(hash_or_height).cloned())
|
|
||||||
.map(Arc::new)
|
|
||||||
.or_else(|| db.sapling_tree(hash_or_height))
|
.or_else(|| db.sapling_tree(hash_or_height))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,9 +152,7 @@ where
|
||||||
// state, we check the most efficient alternative first. (`chain` is always
|
// state, we check the most efficient alternative first. (`chain` is always
|
||||||
// in memory, but `db` stores blocks on disk, with a memory cache.)
|
// in memory, but `db` stores blocks on disk, with a memory cache.)
|
||||||
chain
|
chain
|
||||||
.as_ref()
|
.and_then(|chain| chain.as_ref().orchard_tree(hash_or_height))
|
||||||
.and_then(|chain| chain.as_ref().orchard_tree(hash_or_height).cloned())
|
|
||||||
.map(Arc::new)
|
|
||||||
.or_else(|| db.orchard_tree(hash_or_height))
|
.or_else(|| db.orchard_tree(hash_or_height))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue