-
Notifications
You must be signed in to change notification settings - Fork 113
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
Add invalidate block method and invalidated_blocks field to NonFinalizedState #9167
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,10 @@ | ||
//! State [`tower::Service`] request types. | ||
|
||
use std::{ | ||
collections::{HashMap, HashSet}, | ||
collections::{BTreeMap, HashMap, HashSet}, | ||
ops::{Deref, DerefMut, RangeInclusive}, | ||
sync::Arc, | ||
time::SystemTime, | ||
}; | ||
|
||
use zebra_chain::{ | ||
|
@@ -234,6 +235,18 @@ pub struct ContextuallyVerifiedBlock { | |
pub(crate) chain_value_pool_change: ValueBalance<NegativeAllowed>, | ||
} | ||
|
||
/// Data related to an invalidated block including the [`ContextuallyVerifiedBlock`] and | ||
/// descendants. | ||
#[derive(Clone, Debug)] | ||
pub struct InvalidatedBlockData { | ||
/// The block that was invalidated. | ||
pub block: ContextuallyVerifiedBlock, | ||
/// All descendant blocks that were also removed in order by [`block::Height`]. | ||
pub descendants: BTreeMap<block::Height, ContextuallyVerifiedBlock>, | ||
/// Timestamp in which the block was invalidated. | ||
pub timestamp: SystemTime, | ||
Comment on lines
+246
to
+247
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the intended purpose of this timestamp? |
||
} | ||
|
||
/// Wraps note commitment trees and the history tree together. | ||
/// | ||
/// The default instance represents the treestate that corresponds to the genesis block. | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -6,17 +6,19 @@ use std::{ | |||||||||||||||||
collections::{BTreeSet, HashMap}, | ||||||||||||||||||
mem, | ||||||||||||||||||
sync::Arc, | ||||||||||||||||||
time::SystemTime, | ||||||||||||||||||
}; | ||||||||||||||||||
|
||||||||||||||||||
use chain::UpdateWith; | ||||||||||||||||||
use zebra_chain::{ | ||||||||||||||||||
block::{self, Block}, | ||||||||||||||||||
block::{self, Block, Hash}, | ||||||||||||||||||
parameters::Network, | ||||||||||||||||||
sprout, transparent, | ||||||||||||||||||
}; | ||||||||||||||||||
|
||||||||||||||||||
use crate::{ | ||||||||||||||||||
constants::MAX_NON_FINALIZED_CHAIN_FORKS, | ||||||||||||||||||
request::{ContextuallyVerifiedBlock, FinalizableBlock}, | ||||||||||||||||||
request::{ContextuallyVerifiedBlock, FinalizableBlock, InvalidatedBlockData}, | ||||||||||||||||||
service::{check, finalized_state::ZebraDb}, | ||||||||||||||||||
SemanticallyVerifiedBlock, ValidateContextError, | ||||||||||||||||||
}; | ||||||||||||||||||
|
@@ -45,6 +47,9 @@ pub struct NonFinalizedState { | |||||||||||||||||
/// callers should migrate to `chain_iter().next()`. | ||||||||||||||||||
chain_set: BTreeSet<Arc<Chain>>, | ||||||||||||||||||
|
||||||||||||||||||
/// Invalidated blocks and descendants | ||||||||||||||||||
invalidated_blocks: HashMap<block::Hash, InvalidatedBlockData>, | ||||||||||||||||||
Comment on lines
+50
to
+51
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Optional/Nitpick: Ideally this hash map or its values would be in an I'm also wondering if this could be simplified to be
Suggested change
|
||||||||||||||||||
|
||||||||||||||||||
// Configuration | ||||||||||||||||||
// | ||||||||||||||||||
/// The configured Zcash network. | ||||||||||||||||||
|
@@ -92,6 +97,7 @@ impl Clone for NonFinalizedState { | |||||||||||||||||
Self { | ||||||||||||||||||
chain_set: self.chain_set.clone(), | ||||||||||||||||||
network: self.network.clone(), | ||||||||||||||||||
invalidated_blocks: self.invalidated_blocks.clone(), | ||||||||||||||||||
|
||||||||||||||||||
#[cfg(feature = "getblocktemplate-rpcs")] | ||||||||||||||||||
should_count_metrics: self.should_count_metrics, | ||||||||||||||||||
|
@@ -112,6 +118,7 @@ impl NonFinalizedState { | |||||||||||||||||
NonFinalizedState { | ||||||||||||||||||
chain_set: Default::default(), | ||||||||||||||||||
network: network.clone(), | ||||||||||||||||||
invalidated_blocks: Default::default(), | ||||||||||||||||||
#[cfg(feature = "getblocktemplate-rpcs")] | ||||||||||||||||||
should_count_metrics: true, | ||||||||||||||||||
#[cfg(feature = "progress-bar")] | ||||||||||||||||||
|
@@ -264,6 +271,49 @@ impl NonFinalizedState { | |||||||||||||||||
Ok(()) | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/// Invalidate block with has `block_hash` and all descendants from the non-finalized state. Insert | ||||||||||||||||||
/// the new chain into the chain_set and discard the previous. | ||||||||||||||||||
pub fn invalidate_block(&mut self, block_hash: Hash) { | ||||||||||||||||||
if !self.any_chain_contains(&block_hash) { | ||||||||||||||||||
return; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
let mut chain = self | ||||||||||||||||||
.find_chain(|chain| chain.contains_block_hash(block_hash)) | ||||||||||||||||||
.expect("block hash exist in a chain"); | ||||||||||||||||||
|
||||||||||||||||||
let new_chain = Arc::make_mut(&mut chain); | ||||||||||||||||||
let block_height = new_chain.height_by_hash(block_hash).unwrap(); | ||||||||||||||||||
|
||||||||||||||||||
// Split the new chain at the the `block_hash` and invalidate the block with the | ||||||||||||||||||
// block_hash along with the block's descendants | ||||||||||||||||||
let mut invalidated_blocks = new_chain.blocks.split_off(&block_height); | ||||||||||||||||||
for (_, ctx_block) in invalidated_blocks.iter().rev() { | ||||||||||||||||||
new_chain.revert_chain_with(ctx_block, chain::RevertPosition::Tip); | ||||||||||||||||||
} | ||||||||||||||||||
Comment on lines
+286
to
+293
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nitpick/Optional: Ideally we could move this to a |
||||||||||||||||||
|
||||||||||||||||||
self.invalidated_blocks.insert( | ||||||||||||||||||
block_hash, | ||||||||||||||||||
InvalidatedBlockData { | ||||||||||||||||||
block: invalidated_blocks.remove(&block_height).unwrap(), | ||||||||||||||||||
descendants: invalidated_blocks, | ||||||||||||||||||
timestamp: SystemTime::now(), | ||||||||||||||||||
}, | ||||||||||||||||||
); | ||||||||||||||||||
|
||||||||||||||||||
// If the new chain still contains blocks: | ||||||||||||||||||
// - add the new chain fork or updated chain to the set of recent chains | ||||||||||||||||||
// - remove the chain containing the hash of the block from the chain set | ||||||||||||||||||
if !new_chain.is_empty() { | ||||||||||||||||||
self.insert_with(Arc::new(new_chain.clone()), |chain_set| { | ||||||||||||||||||
chain_set.retain(|c| !c.contains_block_hash(block_hash)) | ||||||||||||||||||
}); | ||||||||||||||||||
|
||||||||||||||||||
self.update_metrics_for_chains(); | ||||||||||||||||||
self.update_metrics_bars(); | ||||||||||||||||||
} | ||||||||||||||||||
Comment on lines
+311
to
+314
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should update the metrics whenever Optional/Nitpick: This method could drop the chain and return early when the invalidated block is the non-finalized chain root block.
Suggested change
|
||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/// Commit block to the non-finalized state as a new chain where its parent | ||||||||||||||||||
/// is the finalized tip. | ||||||||||||||||||
#[tracing::instrument(level = "debug", skip(self, finalized_state, prepared))] | ||||||||||||||||||
|
@@ -578,6 +628,11 @@ impl NonFinalizedState { | |||||||||||||||||
self.chain_set.len() | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/// Return the invalidated blocks. | ||||||||||||||||||
pub fn invalidated_blocks(&self) -> HashMap<block::Hash, InvalidatedBlockData> { | ||||||||||||||||||
self.invalidated_blocks.clone() | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/// Return the chain whose tip block hash is `parent_hash`. | ||||||||||||||||||
/// | ||||||||||||||||||
/// The chain can be an existing chain in the non-finalized state, or a freshly | ||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a suggestion below for removing this struct altogether, but if we're keeping it, minor documentation update: