Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(state): Store history trees by height in the non-finalized state #4928

Merged
merged 5 commits into from
Aug 29, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions zebra-chain/src/history_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,3 +507,11 @@ impl Deref for HistoryTree {
&self.0
}
}

impl PartialEq for HistoryTree {
fn eq(&self, other: &Self) -> bool {
self.as_ref().map(|tree| tree.hash()) == other.as_ref().map(|other_tree| other_tree.hash())
}
}

impl Eq for HistoryTree {}
20 changes: 16 additions & 4 deletions zebra-state/src/service/non_finalized_state/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ pub struct Chain {
/// The ZIP-221 history tree of the tip of this [`Chain`],
/// including all finalized blocks, and the non-finalized `blocks` in this chain.
pub(crate) history_tree: Arc<HistoryTree>,
pub(crate) history_trees_by_height: BTreeMap<block::Height, Arc<HistoryTree>>,

/// The Sprout anchors created by `blocks`.
pub(crate) sprout_anchors: MultiSet<sprout::tree::Root>,
Expand Down Expand Up @@ -161,6 +162,7 @@ impl Chain {
partial_transparent_transfers: Default::default(),
partial_cumulative_work: Default::default(),
history_tree,
history_trees_by_height: Default::default(),
chain_value_pools: finalized_tip_chain_value_pools,
}
}
Expand Down Expand Up @@ -190,12 +192,13 @@ impl Chain {
self.sprout_note_commitment_tree.root() == other.sprout_note_commitment_tree.root() &&
self.sprout_trees_by_anchor == other.sprout_trees_by_anchor &&
self.sapling_note_commitment_tree.root() == other.sapling_note_commitment_tree.root() &&
self.sapling_trees_by_height== other.sapling_trees_by_height &&
self.sapling_trees_by_height == other.sapling_trees_by_height &&
self.orchard_note_commitment_tree.root() == other.orchard_note_commitment_tree.root() &&
self.orchard_trees_by_height== other.orchard_trees_by_height &&
self.orchard_trees_by_height == other.orchard_trees_by_height &&

// history tree
self.history_tree.as_ref().as_ref().map(|tree| tree.hash()) == other.history_tree.as_ref().as_ref().map(|other_tree| other_tree.hash()) &&
// history trees
self.history_tree == other.history_tree &&
self.history_trees_by_height == other.history_trees_by_height &&

// anchors
self.sprout_anchors == other.sprout_anchors &&
Expand Down Expand Up @@ -752,6 +755,7 @@ impl Chain {
partial_transparent_transfers: self.partial_transparent_transfers.clone(),
partial_cumulative_work: self.partial_cumulative_work,
history_tree,
history_trees_by_height: self.history_trees_by_height.clone(),
chain_value_pools: self.chain_value_pools,
}
}
Expand Down Expand Up @@ -836,6 +840,9 @@ impl Chain {
orchard_root,
)?;

self.history_trees_by_height
.insert(height, self.history_tree.clone());

Ok(())
}

Expand Down Expand Up @@ -1035,6 +1042,11 @@ impl UpdateWith<ContextuallyValidBlock> for Chain {
// This method is called on two scenarios:
// - When popping the root: the history tree does not change.
// - When popping the tip: the history tree is rebuilt in fork().
//
// However, `history_trees_by_height` is reverted.
self.history_trees_by_height
.remove(&height)
.expect("History tree must be present if block was added to chain");

// for each transaction in block
for (transaction, transaction_hash) in
Expand Down
3 changes: 2 additions & 1 deletion zebra-state/src/service/non_finalized_state/tests/prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -613,8 +613,9 @@ fn different_blocks_different_chains() -> Result<()> {
chain1.orchard_note_commitment_tree = chain2.orchard_note_commitment_tree.clone();
chain1.orchard_trees_by_height = chain2.orchard_trees_by_height.clone();

// history tree
// history trees
chain1.history_tree = chain2.history_tree.clone();
chain1.history_trees_by_height = chain2.history_trees_by_height.clone();

// anchors
chain1.sprout_anchors = chain2.sprout_anchors.clone();
Expand Down