@@ -9,7 +9,7 @@ use std::{
99} ;
1010
1111use zebra_chain:: {
12- block:: { self , Block } ,
12+ block:: { self , Block , Hash } ,
1313 parameters:: Network ,
1414 sprout, transparent,
1515} ;
@@ -45,6 +45,10 @@ pub struct NonFinalizedState {
4545 /// callers should migrate to `chain_iter().next()`.
4646 chain_set : BTreeSet < Arc < Chain > > ,
4747
48+ /// Blocks that have been invalidated in, and removed from, the non finalized
49+ /// state.
50+ invalidated_blocks : HashMap < Hash , Arc < Vec < ContextuallyVerifiedBlock > > > ,
51+
4852 // Configuration
4953 //
5054 /// The configured Zcash network.
@@ -92,6 +96,7 @@ impl Clone for NonFinalizedState {
9296 Self {
9397 chain_set : self . chain_set . clone ( ) ,
9498 network : self . network . clone ( ) ,
99+ invalidated_blocks : self . invalidated_blocks . clone ( ) ,
95100
96101 #[ cfg( feature = "getblocktemplate-rpcs" ) ]
97102 should_count_metrics : self . should_count_metrics ,
@@ -112,6 +117,7 @@ impl NonFinalizedState {
112117 NonFinalizedState {
113118 chain_set : Default :: default ( ) ,
114119 network : network. clone ( ) ,
120+ invalidated_blocks : Default :: default ( ) ,
115121 #[ cfg( feature = "getblocktemplate-rpcs" ) ]
116122 should_count_metrics : true ,
117123 #[ cfg( feature = "progress-bar" ) ]
@@ -264,6 +270,37 @@ impl NonFinalizedState {
264270 Ok ( ( ) )
265271 }
266272
273+ /// Invalidate block with hash `block_hash` and all descendants from the non-finalized state. Insert
274+ /// the new chain into the chain_set and discard the previous.
275+ pub fn invalidate_block ( & mut self , block_hash : Hash ) {
276+ let Some ( chain) = self . find_chain ( |chain| chain. contains_block_hash ( block_hash) ) else {
277+ return ;
278+ } ;
279+
280+ let invalidated_blocks = if chain. non_finalized_root_hash ( ) == block_hash {
281+ self . chain_set . remove ( & chain) ;
282+ chain. blocks . values ( ) . cloned ( ) . collect ( )
283+ } else {
284+ let ( new_chain, invalidated_blocks) = chain
285+ . invalidate_block ( block_hash)
286+ . expect ( "already checked that chain contains hash" ) ;
287+
288+ // Add the new chain fork or updated chain to the set of recent chains, and
289+ // remove the chain containing the hash of the block from chain set
290+ self . insert_with ( Arc :: new ( new_chain. clone ( ) ) , |chain_set| {
291+ chain_set. retain ( |c| !c. contains_block_hash ( block_hash) )
292+ } ) ;
293+
294+ invalidated_blocks
295+ } ;
296+
297+ self . invalidated_blocks
298+ . insert ( block_hash, Arc :: new ( invalidated_blocks) ) ;
299+
300+ self . update_metrics_for_chains ( ) ;
301+ self . update_metrics_bars ( ) ;
302+ }
303+
267304 /// Commit block to the non-finalized state as a new chain where its parent
268305 /// is the finalized tip.
269306 #[ tracing:: instrument( level = "debug" , skip( self , finalized_state, prepared) ) ]
@@ -586,6 +623,11 @@ impl NonFinalizedState {
586623 self . chain_set . len ( )
587624 }
588625
626+ /// Return the invalidated blocks.
627+ pub fn invalidated_blocks ( & self ) -> HashMap < block:: Hash , Arc < Vec < ContextuallyVerifiedBlock > > > {
628+ self . invalidated_blocks . clone ( )
629+ }
630+
589631 /// Return the chain whose tip block hash is `parent_hash`.
590632 ///
591633 /// The chain can be an existing chain in the non-finalized state, or a freshly
0 commit comments