change(state): Refactor the structure of finalizable blocks (#7035)

* Add and use `FinalizableBlock`

This commit adds `FinalizableBlock`, and uses it instead of
`ContextuallyVerifiedBlockWithTrees` in `commit_finalized_direct()`

* Use `ContextuallyVerifiedBlockWithTrees`

This commit passes `ContextuallyVerifiedBlockWithTrees` instead of
passing separate `finalized`, `history_tree` and `note_commitment_trees`
when storing blocks in the finalized state.

* Apply suggestions from code review

Co-authored-by: teor <teor@riseup.net>

* add docs to new methods

* fix existing doc

* rename `ContextuallyVerifiedBlockWithTrees` to `SemanticallyVerifiedBlockWithTrees`

* Refactor docs

* Refactor comments

* Add missing docs, fix typo

* Fix rustfmt

---------

Co-authored-by: teor <teor@riseup.net>
Co-authored-by: Alfredo Garcia <oxarbitrage@gmail.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
Marek 2023-06-27 10:58:14 +02:00 committed by GitHub
parent 941be2965c
commit 1f1d04b547
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 168 additions and 140 deletions

View File

@ -255,46 +255,65 @@ impl Treestate {
/// when committing a block. The associated treestate is passed so that the /// when committing a block. The associated treestate is passed so that the
/// finalized state does not have to retrieve the previous treestate from the /// finalized state does not have to retrieve the previous treestate from the
/// database and recompute a new one. /// database and recompute a new one.
pub struct ContextuallyVerifiedBlockWithTrees { pub struct SemanticallyVerifiedBlockWithTrees {
/// A block ready to be committed. /// A block ready to be committed.
pub block: SemanticallyVerifiedBlock, pub verified: SemanticallyVerifiedBlock,
/// The tresstate associated with the block. /// The tresstate associated with the block.
pub treestate: Option<Treestate>, pub treestate: Treestate,
} }
impl ContextuallyVerifiedBlockWithTrees { /// Contains a block ready to be committed.
///
/// Zebra's state service passes this `enum` over to the finalized state
/// when committing a block.
pub enum FinalizableBlock {
Checkpoint {
checkpoint_verified: CheckpointVerifiedBlock,
},
Contextual {
contextually_verified: ContextuallyVerifiedBlock,
treestate: Treestate,
},
}
impl FinalizableBlock {
/// Create a new [`FinalizableBlock`] given a [`ContextuallyVerifiedBlock`].
pub fn new(contextually_verified: ContextuallyVerifiedBlock, treestate: Treestate) -> Self { pub fn new(contextually_verified: ContextuallyVerifiedBlock, treestate: Treestate) -> Self {
Self { Self::Contextual {
block: SemanticallyVerifiedBlock::from(contextually_verified), contextually_verified,
treestate: Some(treestate), treestate,
}
}
#[cfg(test)]
/// Extract a [`Block`] from a [`FinalizableBlock`] variant.
pub fn inner_block(&self) -> Arc<Block> {
match self {
FinalizableBlock::Checkpoint {
checkpoint_verified,
} => checkpoint_verified.block.clone(),
FinalizableBlock::Contextual {
contextually_verified,
..
} => contextually_verified.block.clone(),
} }
} }
} }
impl From<Arc<Block>> for ContextuallyVerifiedBlockWithTrees { impl From<CheckpointVerifiedBlock> for FinalizableBlock {
fn from(block: Arc<Block>) -> Self {
Self::from(SemanticallyVerifiedBlock::from(block))
}
}
impl From<SemanticallyVerifiedBlock> for ContextuallyVerifiedBlockWithTrees {
fn from(semantically_verified: SemanticallyVerifiedBlock) -> Self {
Self {
block: semantically_verified,
treestate: None,
}
}
}
impl From<CheckpointVerifiedBlock> for ContextuallyVerifiedBlockWithTrees {
fn from(checkpoint_verified: CheckpointVerifiedBlock) -> Self { fn from(checkpoint_verified: CheckpointVerifiedBlock) -> Self {
Self { Self::Checkpoint {
block: checkpoint_verified.0, checkpoint_verified,
treestate: None,
} }
} }
} }
impl From<Arc<Block>> for FinalizableBlock {
fn from(block: Arc<Block>) -> Self {
Self::from(CheckpointVerifiedBlock::from(block))
}
}
impl From<&SemanticallyVerifiedBlock> for SemanticallyVerifiedBlock { impl From<&SemanticallyVerifiedBlock> for SemanticallyVerifiedBlock {
fn from(semantically_verified: &SemanticallyVerifiedBlock) -> Self { fn from(semantically_verified: &SemanticallyVerifiedBlock) -> Self {
semantically_verified.clone() semantically_verified.clone()
@ -413,6 +432,12 @@ impl From<ContextuallyVerifiedBlock> for SemanticallyVerifiedBlock {
} }
} }
impl From<CheckpointVerifiedBlock> for SemanticallyVerifiedBlock {
fn from(checkpoint_verified: CheckpointVerifiedBlock) -> Self {
checkpoint_verified.0
}
}
impl Deref for CheckpointVerifiedBlock { impl Deref for CheckpointVerifiedBlock {
type Target = SemanticallyVerifiedBlock; type Target = SemanticallyVerifiedBlock;

View File

@ -23,7 +23,7 @@ use std::{
use zebra_chain::{block, parameters::Network}; use zebra_chain::{block, parameters::Network};
use crate::{ use crate::{
request::ContextuallyVerifiedBlockWithTrees, request::{FinalizableBlock, SemanticallyVerifiedBlockWithTrees, Treestate},
service::{check, QueuedCheckpointVerified}, service::{check, QueuedCheckpointVerified},
BoxError, CheckpointVerifiedBlock, CloneError, Config, BoxError, CheckpointVerifiedBlock, CloneError, Config,
}; };
@ -225,53 +225,25 @@ impl FinalizedState {
#[allow(clippy::unwrap_in_result)] #[allow(clippy::unwrap_in_result)]
pub fn commit_finalized_direct( pub fn commit_finalized_direct(
&mut self, &mut self,
contextually_verified_with_trees: ContextuallyVerifiedBlockWithTrees, finalizable_block: FinalizableBlock,
source: &str, source: &str,
) -> Result<block::Hash, BoxError> { ) -> Result<block::Hash, BoxError> {
let finalized = contextually_verified_with_trees.block; let (height, hash, finalized) = match finalizable_block {
let committed_tip_hash = self.db.finalized_tip_hash(); FinalizableBlock::Checkpoint {
let committed_tip_height = self.db.finalized_tip_height(); checkpoint_verified,
} => {
// Checkpoint-verified blocks don't have an associated treestate, so we retrieve the
// treestate of the finalized tip from the database and update it for the block
// being committed, assuming the retrieved treestate is the parent block's
// treestate. Later on, this function proves this assumption by asserting that the
// finalized tip is the parent block of the block being committed.
// Assert that callers (including unit tests) get the chain order correct let block = checkpoint_verified.block.clone();
if self.db.is_empty() {
assert_eq!(
committed_tip_hash, finalized.block.header.previous_block_hash,
"the first block added to an empty state must be a genesis block, source: {source}",
);
assert_eq!(
block::Height(0),
finalized.height,
"cannot commit genesis: invalid height, source: {source}",
);
} else {
assert_eq!(
committed_tip_height.expect("state must have a genesis block committed") + 1,
Some(finalized.height),
"committed block height must be 1 more than the finalized tip height, source: {source}",
);
assert_eq!(
committed_tip_hash, finalized.block.header.previous_block_hash,
"committed block must be a child of the finalized tip, source: {source}",
);
}
let (history_tree, note_commitment_trees) = match contextually_verified_with_trees.treestate
{
// If the treestate associated with the block was supplied, use it
// without recomputing it.
Some(ref treestate) => (
treestate.history_tree.clone(),
treestate.note_commitment_trees.clone(),
),
// If the treestate was not supplied, retrieve a previous treestate
// from the database, and update it for the block being committed.
None => {
let mut history_tree = self.db.history_tree(); let mut history_tree = self.db.history_tree();
let mut note_commitment_trees = self.db.note_commitment_trees(); let mut note_commitment_trees = self.db.note_commitment_trees();
// Update the note commitment trees. // Update the note commitment trees.
note_commitment_trees.update_trees_parallel(&finalized.block)?; note_commitment_trees.update_trees_parallel(&block)?;
// Check the block commitment if the history tree was not // Check the block commitment if the history tree was not
// supplied by the non-finalized state. Note that we don't do // supplied by the non-finalized state. Note that we don't do
@ -291,7 +263,7 @@ impl FinalizedState {
// TODO: run this CPU-intensive cryptography in a parallel rayon // TODO: run this CPU-intensive cryptography in a parallel rayon
// thread, if it shows up in profiles // thread, if it shows up in profiles
check::block_commitment_is_valid_for_chain_history( check::block_commitment_is_valid_for_chain_history(
finalized.block.clone(), block.clone(),
self.network, self.network,
&history_tree, &history_tree,
)?; )?;
@ -303,30 +275,64 @@ impl FinalizedState {
let history_tree_mut = Arc::make_mut(&mut history_tree); let history_tree_mut = Arc::make_mut(&mut history_tree);
let sapling_root = note_commitment_trees.sapling.root(); let sapling_root = note_commitment_trees.sapling.root();
let orchard_root = note_commitment_trees.orchard.root(); let orchard_root = note_commitment_trees.orchard.root();
history_tree_mut.push( history_tree_mut.push(self.network(), block.clone(), sapling_root, orchard_root)?;
self.network(),
finalized.block.clone(),
sapling_root,
orchard_root,
)?;
(history_tree, note_commitment_trees) (
checkpoint_verified.height,
checkpoint_verified.hash,
SemanticallyVerifiedBlockWithTrees {
verified: checkpoint_verified.0,
treestate: Treestate {
note_commitment_trees,
history_tree,
},
},
)
} }
FinalizableBlock::Contextual {
contextually_verified,
treestate,
} => (
contextually_verified.height,
contextually_verified.hash,
SemanticallyVerifiedBlockWithTrees {
verified: contextually_verified.into(),
treestate,
},
),
}; };
let finalized_height = finalized.height; let committed_tip_hash = self.db.finalized_tip_hash();
let finalized_hash = finalized.hash; let committed_tip_height = self.db.finalized_tip_height();
// Assert that callers (including unit tests) get the chain order correct
if self.db.is_empty() {
assert_eq!(
committed_tip_hash, finalized.verified.block.header.previous_block_hash,
"the first block added to an empty state must be a genesis block, source: {source}",
);
assert_eq!(
block::Height(0),
height,
"cannot commit genesis: invalid height, source: {source}",
);
} else {
assert_eq!(
committed_tip_height.expect("state must have a genesis block committed") + 1,
Some(height),
"committed block height must be 1 more than the finalized tip height, source: {source}",
);
assert_eq!(
committed_tip_hash, finalized.verified.block.header.previous_block_hash,
"committed block must be a child of the finalized tip, source: {source}",
);
}
#[cfg(feature = "elasticsearch")] #[cfg(feature = "elasticsearch")]
let finalized_block = finalized.block.clone(); let finalized_block = finalized.verified.block.clone();
let result = self.db.write_block( let result = self.db.write_block(finalized, self.network, source);
finalized,
history_tree,
note_commitment_trees,
self.network,
source,
);
if result.is_ok() { if result.is_ok() {
// Save blocks to elasticsearch if the feature is enabled. // Save blocks to elasticsearch if the feature is enabled.
@ -334,10 +340,10 @@ impl FinalizedState {
self.elasticsearch(&finalized_block); self.elasticsearch(&finalized_block);
// TODO: move the stop height check to the syncer (#3442) // TODO: move the stop height check to the syncer (#3442)
if self.is_at_stop_height(finalized_height) { if self.is_at_stop_height(height) {
tracing::info!( tracing::info!(
height = ?finalized_height, ?height,
hash = ?finalized_hash, ?hash,
block_source = ?source, block_source = ?source,
"stopping at configured height, flushing database to disk" "stopping at configured height, flushing database to disk"
); );

View File

@ -19,9 +19,7 @@ use itertools::Itertools;
use zebra_chain::{ use zebra_chain::{
amount::NonNegative, amount::NonNegative,
block::{self, Block, Height}, block::{self, Block, Height},
history_tree::HistoryTree,
orchard, orchard,
parallel::tree::NoteCommitmentTrees,
parameters::{Network, GENESIS_PREVIOUS_BLOCK_HASH}, parameters::{Network, GENESIS_PREVIOUS_BLOCK_HASH},
sapling, sapling,
serialization::TrustedPreallocate, serialization::TrustedPreallocate,
@ -31,6 +29,7 @@ use zebra_chain::{
}; };
use crate::{ use crate::{
request::SemanticallyVerifiedBlockWithTrees,
service::finalized_state::{ service::finalized_state::{
disk_db::{DiskDb, DiskWriteBatch, ReadDisk, WriteDisk}, disk_db::{DiskDb, DiskWriteBatch, ReadDisk, WriteDisk},
disk_format::{ disk_format::{
@ -281,15 +280,12 @@ impl ZebraDb {
/// - Propagates any errors from updating history and note commitment trees /// - Propagates any errors from updating history and note commitment trees
pub(in super::super) fn write_block( pub(in super::super) fn write_block(
&mut self, &mut self,
finalized: SemanticallyVerifiedBlock, finalized: SemanticallyVerifiedBlockWithTrees,
history_tree: Arc<HistoryTree>,
note_commitment_trees: NoteCommitmentTrees,
network: Network, network: Network,
source: &str, source: &str,
) -> Result<block::Hash, BoxError> { ) -> Result<block::Hash, BoxError> {
let finalized_hash = finalized.hash;
let tx_hash_indexes: HashMap<transaction::Hash, usize> = finalized let tx_hash_indexes: HashMap<transaction::Hash, usize> = finalized
.verified
.transaction_hashes .transaction_hashes
.iter() .iter()
.enumerate() .enumerate()
@ -302,11 +298,12 @@ impl ZebraDb {
// simplify the spent_utxos location lookup code, // simplify the spent_utxos location lookup code,
// and remove the extra new_outputs_by_out_loc argument // and remove the extra new_outputs_by_out_loc argument
let new_outputs_by_out_loc: BTreeMap<OutputLocation, transparent::Utxo> = finalized let new_outputs_by_out_loc: BTreeMap<OutputLocation, transparent::Utxo> = finalized
.verified
.new_outputs .new_outputs
.iter() .iter()
.map(|(outpoint, ordered_utxo)| { .map(|(outpoint, ordered_utxo)| {
( (
lookup_out_loc(finalized.height, outpoint, &tx_hash_indexes), lookup_out_loc(finalized.verified.height, outpoint, &tx_hash_indexes),
ordered_utxo.utxo.clone(), ordered_utxo.utxo.clone(),
) )
}) })
@ -315,6 +312,7 @@ impl ZebraDb {
// Get a list of the spent UTXOs, before we delete any from the database // Get a list of the spent UTXOs, before we delete any from the database
let spent_utxos: Vec<(transparent::OutPoint, OutputLocation, transparent::Utxo)> = let spent_utxos: Vec<(transparent::OutPoint, OutputLocation, transparent::Utxo)> =
finalized finalized
.verified
.block .block
.transactions .transactions
.iter() .iter()
@ -326,12 +324,13 @@ impl ZebraDb {
// Some utxos are spent in the same block, so they will be in // Some utxos are spent in the same block, so they will be in
// `tx_hash_indexes` and `new_outputs` // `tx_hash_indexes` and `new_outputs`
self.output_location(&outpoint).unwrap_or_else(|| { self.output_location(&outpoint).unwrap_or_else(|| {
lookup_out_loc(finalized.height, &outpoint, &tx_hash_indexes) lookup_out_loc(finalized.verified.height, &outpoint, &tx_hash_indexes)
}), }),
self.utxo(&outpoint) self.utxo(&outpoint)
.map(|ordered_utxo| ordered_utxo.utxo) .map(|ordered_utxo| ordered_utxo.utxo)
.or_else(|| { .or_else(|| {
finalized finalized
.verified
.new_outputs .new_outputs
.get(&outpoint) .get(&outpoint)
.map(|ordered_utxo| ordered_utxo.utxo.clone()) .map(|ordered_utxo| ordered_utxo.utxo.clone())
@ -356,6 +355,7 @@ impl ZebraDb {
.values() .values()
.chain( .chain(
finalized finalized
.verified
.new_outputs .new_outputs
.values() .values()
.map(|ordered_utxo| &ordered_utxo.utxo), .map(|ordered_utxo| &ordered_utxo.utxo),
@ -376,13 +376,11 @@ impl ZebraDb {
// In case of errors, propagate and do not write the batch. // In case of errors, propagate and do not write the batch.
batch.prepare_block_batch( batch.prepare_block_batch(
&self.db, &self.db,
finalized, &finalized,
new_outputs_by_out_loc, new_outputs_by_out_loc,
spent_utxos_by_outpoint, spent_utxos_by_outpoint,
spent_utxos_by_out_loc, spent_utxos_by_out_loc,
address_balances, address_balances,
history_tree,
note_commitment_trees,
self.finalized_value_pool(), self.finalized_value_pool(),
)?; )?;
@ -390,7 +388,7 @@ impl ZebraDb {
tracing::trace!(?source, "committed block from"); tracing::trace!(?source, "committed block from");
Ok(finalized_hash) Ok(finalized.verified.hash)
} }
} }
@ -429,25 +427,16 @@ impl DiskWriteBatch {
pub fn prepare_block_batch( pub fn prepare_block_batch(
&mut self, &mut self,
db: &DiskDb, db: &DiskDb,
finalized: SemanticallyVerifiedBlock, finalized: &SemanticallyVerifiedBlockWithTrees,
new_outputs_by_out_loc: BTreeMap<OutputLocation, transparent::Utxo>, new_outputs_by_out_loc: BTreeMap<OutputLocation, transparent::Utxo>,
spent_utxos_by_outpoint: HashMap<transparent::OutPoint, transparent::Utxo>, spent_utxos_by_outpoint: HashMap<transparent::OutPoint, transparent::Utxo>,
spent_utxos_by_out_loc: BTreeMap<OutputLocation, transparent::Utxo>, spent_utxos_by_out_loc: BTreeMap<OutputLocation, transparent::Utxo>,
address_balances: HashMap<transparent::Address, AddressBalanceLocation>, address_balances: HashMap<transparent::Address, AddressBalanceLocation>,
history_tree: Arc<HistoryTree>,
note_commitment_trees: NoteCommitmentTrees,
value_pool: ValueBalance<NonNegative>, value_pool: ValueBalance<NonNegative>,
) -> Result<(), BoxError> { ) -> Result<(), BoxError> {
let SemanticallyVerifiedBlock {
block,
hash,
height,
..
} = &finalized;
// Commit block and transaction data. // Commit block and transaction data.
// (Transaction indexes, note commitments, and UTXOs are committed later.) // (Transaction indexes, note commitments, and UTXOs are committed later.)
self.prepare_block_header_and_transaction_data_batch(db, &finalized)?; self.prepare_block_header_and_transaction_data_batch(db, &finalized.verified)?;
// # Consensus // # Consensus
// //
@ -458,28 +447,37 @@ impl DiskWriteBatch {
// //
// By returning early, Zebra commits the genesis block and transaction data, // By returning early, Zebra commits the genesis block and transaction data,
// but it ignores the genesis UTXO and value pool updates. // but it ignores the genesis UTXO and value pool updates.
if self.prepare_genesis_batch(db, &finalized) { if self.prepare_genesis_batch(db, &finalized.verified) {
return Ok(()); return Ok(());
} }
// Commit transaction indexes // Commit transaction indexes
self.prepare_transparent_transaction_batch( self.prepare_transparent_transaction_batch(
db, db,
&finalized, &finalized.verified,
&new_outputs_by_out_loc, &new_outputs_by_out_loc,
&spent_utxos_by_outpoint, &spent_utxos_by_outpoint,
&spent_utxos_by_out_loc, &spent_utxos_by_out_loc,
address_balances, address_balances,
)?; )?;
self.prepare_shielded_transaction_batch(db, &finalized)?; self.prepare_shielded_transaction_batch(db, &finalized.verified)?;
self.prepare_note_commitment_batch(db, &finalized, note_commitment_trees, history_tree)?; self.prepare_note_commitment_batch(db, finalized)?;
// Commit UTXOs and value pools // Commit UTXOs and value pools
self.prepare_chain_value_pools_batch(db, &finalized, spent_utxos_by_outpoint, value_pool)?; self.prepare_chain_value_pools_batch(
db,
&finalized.verified,
spent_utxos_by_outpoint,
value_pool,
)?;
// The block has passed contextual validation, so update the metrics // The block has passed contextual validation, so update the metrics
block_precommit_metrics(block, *hash, *height); block_precommit_metrics(
&finalized.verified.block,
finalized.verified.hash,
finalized.verified.height,
);
Ok(()) Ok(())
} }

View File

@ -21,6 +21,7 @@ use zebra_chain::{
}; };
use crate::{ use crate::{
request::SemanticallyVerifiedBlockWithTrees,
service::finalized_state::{ service::finalized_state::{
disk_db::{DiskDb, DiskWriteBatch, ReadDisk, WriteDisk}, disk_db::{DiskDb, DiskWriteBatch, ReadDisk, WriteDisk},
zebra_db::ZebraDb, zebra_db::ZebraDb,
@ -69,15 +70,14 @@ impl DiskWriteBatch {
pub fn prepare_history_batch( pub fn prepare_history_batch(
&mut self, &mut self,
db: &DiskDb, db: &DiskDb,
finalized: &SemanticallyVerifiedBlock, finalized: &SemanticallyVerifiedBlockWithTrees,
history_tree: Arc<HistoryTree>,
) -> Result<(), BoxError> { ) -> Result<(), BoxError> {
let history_tree_cf = db.cf_handle("history_tree").unwrap(); let history_tree_cf = db.cf_handle("history_tree").unwrap();
let SemanticallyVerifiedBlock { height, .. } = finalized; let height = finalized.verified.height;
// Update the tree in state // Update the tree in state
let current_tip_height = *height - 1; let current_tip_height = height - 1;
if let Some(h) = current_tip_height { if let Some(h) = current_tip_height {
self.zs_delete(&history_tree_cf, h); self.zs_delete(&history_tree_cf, h);
} }
@ -87,7 +87,7 @@ impl DiskWriteBatch {
// Otherwise, the ReadStateService could access a height // Otherwise, the ReadStateService could access a height
// that was just deleted by a concurrent StateService write. // that was just deleted by a concurrent StateService write.
// This requires a database version update. // This requires a database version update.
if let Some(history_tree) = history_tree.as_ref().as_ref() { if let Some(history_tree) = finalized.treestate.history_tree.as_ref().as_ref() {
self.zs_insert(&history_tree_cf, height, history_tree); self.zs_insert(&history_tree_cf, height, history_tree);
} }

View File

@ -15,11 +15,12 @@
use std::sync::Arc; use std::sync::Arc;
use zebra_chain::{ use zebra_chain::{
block::Height, history_tree::HistoryTree, orchard, parallel::tree::NoteCommitmentTrees, block::Height, orchard, parallel::tree::NoteCommitmentTrees, sapling, sprout,
sapling, sprout, transaction::Transaction, transaction::Transaction,
}; };
use crate::{ use crate::{
request::SemanticallyVerifiedBlockWithTrees,
service::finalized_state::{ service::finalized_state::{
disk_db::{DiskDb, DiskWriteBatch, ReadDisk, WriteDisk}, disk_db::{DiskDb, DiskWriteBatch, ReadDisk, WriteDisk},
zebra_db::ZebraDb, zebra_db::ZebraDb,
@ -264,9 +265,7 @@ impl DiskWriteBatch {
pub fn prepare_note_commitment_batch( pub fn prepare_note_commitment_batch(
&mut self, &mut self,
db: &DiskDb, db: &DiskDb,
finalized: &SemanticallyVerifiedBlock, finalized: &SemanticallyVerifiedBlockWithTrees,
note_commitment_trees: NoteCommitmentTrees,
history_tree: Arc<HistoryTree>,
) -> Result<(), BoxError> { ) -> Result<(), BoxError> {
let sprout_anchors = db.cf_handle("sprout_anchors").unwrap(); let sprout_anchors = db.cf_handle("sprout_anchors").unwrap();
let sapling_anchors = db.cf_handle("sapling_anchors").unwrap(); let sapling_anchors = db.cf_handle("sapling_anchors").unwrap();
@ -276,7 +275,8 @@ impl DiskWriteBatch {
let sapling_note_commitment_tree_cf = db.cf_handle("sapling_note_commitment_tree").unwrap(); let sapling_note_commitment_tree_cf = db.cf_handle("sapling_note_commitment_tree").unwrap();
let orchard_note_commitment_tree_cf = db.cf_handle("orchard_note_commitment_tree").unwrap(); let orchard_note_commitment_tree_cf = db.cf_handle("orchard_note_commitment_tree").unwrap();
let SemanticallyVerifiedBlock { height, .. } = finalized; let height = finalized.verified.height;
let note_commitment_trees = finalized.treestate.note_commitment_trees.clone();
// Use the cached values that were previously calculated in parallel. // Use the cached values that were previously calculated in parallel.
let sprout_root = note_commitment_trees.sprout.root(); let sprout_root = note_commitment_trees.sprout.root();
@ -290,7 +290,7 @@ impl DiskWriteBatch {
self.zs_insert(&orchard_anchors, orchard_root, ()); self.zs_insert(&orchard_anchors, orchard_root, ());
// Delete the previously stored Sprout note commitment tree. // Delete the previously stored Sprout note commitment tree.
let current_tip_height = *height - 1; let current_tip_height = height - 1;
if let Some(h) = current_tip_height { if let Some(h) = current_tip_height {
self.zs_delete(&sprout_note_commitment_tree_cf, h); self.zs_delete(&sprout_note_commitment_tree_cf, h);
} }
@ -317,7 +317,7 @@ impl DiskWriteBatch {
note_commitment_trees.orchard, note_commitment_trees.orchard,
); );
self.prepare_history_batch(db, finalized, history_tree) self.prepare_history_batch(db, finalized)
} }
/// Prepare a database batch containing the initial note commitment trees, /// Prepare a database batch containing the initial note commitment trees,

View File

@ -16,7 +16,7 @@ use zebra_chain::{
use crate::{ use crate::{
constants::MAX_NON_FINALIZED_CHAIN_FORKS, constants::MAX_NON_FINALIZED_CHAIN_FORKS,
request::{ContextuallyVerifiedBlock, ContextuallyVerifiedBlockWithTrees}, request::{ContextuallyVerifiedBlock, FinalizableBlock},
service::{check, finalized_state::ZebraDb}, service::{check, finalized_state::ZebraDb},
SemanticallyVerifiedBlock, ValidateContextError, SemanticallyVerifiedBlock, ValidateContextError,
}; };
@ -174,7 +174,7 @@ impl NonFinalizedState {
/// Finalize the lowest height block in the non-finalized portion of the best /// Finalize the lowest height block in the non-finalized portion of the best
/// chain and update all side-chains to match. /// chain and update all side-chains to match.
pub fn finalize(&mut self) -> ContextuallyVerifiedBlockWithTrees { pub fn finalize(&mut self) -> FinalizableBlock {
// Chain::cmp uses the partial cumulative work, and the hash of the tip block. // Chain::cmp uses the partial cumulative work, and the hash of the tip block.
// Neither of these fields has interior mutability. // Neither of these fields has interior mutability.
// (And when the tip block is dropped for a chain, the chain is also dropped.) // (And when the tip block is dropped for a chain, the chain is also dropped.)
@ -226,7 +226,7 @@ impl NonFinalizedState {
self.update_metrics_for_chains(); self.update_metrics_for_chains();
// Add the treestate to the finalized block. // Add the treestate to the finalized block.
ContextuallyVerifiedBlockWithTrees::new(best_chain_root, root_treestate) FinalizableBlock::new(best_chain_root, root_treestate)
} }
/// Commit block to the non-finalized state, on top of: /// Commit block to the non-finalized state, on top of:

View File

@ -213,13 +213,12 @@ fn finalize_pops_from_best_chain_for_network(network: Network) -> Result<()> {
state.commit_block(block2.clone().prepare(), &finalized_state)?; state.commit_block(block2.clone().prepare(), &finalized_state)?;
state.commit_block(child.prepare(), &finalized_state)?; state.commit_block(child.prepare(), &finalized_state)?;
let finalized_with_trees = state.finalize(); let finalized = state.finalize().inner_block();
let finalized = finalized_with_trees.block;
assert_eq!(block1, finalized.block);
let finalized_with_trees = state.finalize(); assert_eq!(block1, finalized);
let finalized = finalized_with_trees.block;
assert_eq!(block2, finalized.block); let finalized = state.finalize().inner_block();
assert_eq!(block2, finalized);
assert!(state.best_chain().is_none()); assert!(state.best_chain().is_none());